This commit adds mainly buffer pointer and length duplication and checks,
but also some hamming distance and return values checking improvements.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
This reduces the code size by not compiling in unnecessary info structures
when using only 128 bit AES.
Co-authored by: AnttiKauppila <antti.kauppila@arm.com>
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
The change applies to the places where we prevent double synchronous
FI attacks with random delay, and where we do not respond to their
detection. The response to such an attack should be to return the
appropriate error code.
Signed-off-by: Piotr Nowicki <piotr.nowicki@arm.com>
Since the mbed TLS implementation of rng wrapper returns the size of random
data generated upon success - check for it explicitly.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
Lack of this requirement caused warning when compiling the
x509 test suites with config-thread.h from example configs,
resulting in an error when running from test-ref-configs.pl.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
Section 4.2.8 of RFC 6347 describes how to handle the case of a DTLS client
establishing a new connection using the same UDP quartet as an already active
connection, which we implement under the compile option
MBEDTLS_SSL_DLTS_CLIENT_PORT_REUSE. Relevant excerpts:
[the server] MUST NOT destroy the existing
association until the client has demonstrated reachability either by
completing a cookie exchange or by completing a complete handshake
including delivering a verifiable Finished message.
[...]
The reachability requirement prevents
off-path/blind attackers from destroying associations merely by
sending forged ClientHellos.
Our code chooses to use a cookie exchange for establishing reachability, but
unfortunately that check was effectively removed in a recent refactoring,
which changed what value ssl_handle_possible_reconnect() needs to return in
order for ssl_get_next_record() (introduced in that refactoring) to take the
proper action. Unfortunately, in addition to changing the value, the
refactoring also changed a return statement to an assignment to the ret
variable, causing the function to reach the code for a valid cookie, which
immediately destroys the existing association, effectively bypassing the
cookie verification.
This commit fixes that by immediately returning after sending a
HelloVerifyRequest when a ClientHello without a valid cookie is found. It also
updates the description of the function to reflect the new return value
convention (the refactoring updated the code but not the documentation).
The commit that changed the return value convention (and introduced the bug)
is 2fddd3765e, whose commit message explains the
change.
Note: this bug also indirectly caused the ssl-opt.sh test case "DTLS client
reconnect from same port: reconnect" to occasionally fail due to a race
condition between the reception of the ClientHello carrying a valid cookie and
the closure of the connection by the server after noticing the ClientHello
didn't carry a valid cookie after it incorrectly destroyed the previous
connection, that could cause that ClientHello to be invisible to the server
(if that message reaches the server just before it does `net_close()`). A
welcome side effect of this commit is to remove that race condition, as the
new connection will immediately start with a ClientHello carrying a valid
cookie in the SSL input buffer, so the server will not call `net_close()` and
not risk discarding a better ClientHello that arrived in the meantime.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
Conflicts:
mbedtls.doxyfile - PROJECT_NAME - mbed TLS v2.16.6 chosen.
doc_mainpage.h - mbed TLS v2.16.6 version chosen.
hmac_drbg.h - line 260, extended description chosen.
- line 313, extended description chosen.
- line 338, extended description chosen.
version.h - 2.16.6 chosen.
CMakeLists.txt - 2.16.6 chosen.
test_suite_version.data - 2.16.6 chosen.
Makefile - 141 - manual correction - baremetal version of C_SOURCE_FILES
with variables for directories plus 2.16.6 CTAGS addition.
pkparse.c - lines 846 onwards - the asn1_get_nonzero_mpi implementation chosen.
ssl_tls.c - line 5269 - edited manually, left the ret=0, because baremetal has
a different behaviour since commit 87b5626, but added a debug
message that's new in 2.16.6.
all.sh:
- component_build_deprecated - chosen the refactored version from 2.16.6,
but with extra flags from baremetal.
- rest of the _no_xxx tests - merged make options to have PTHREAD=1 and
other changes from 2.16.6 (like -O1 instead of -O0).
- component_build_arm_none_eabi_gcc_no_64bit_multiplication - added
TINYCRYPT_BUILD=0 to the 2.16.6 version of make.
x509/req_app.c - left baremetal log but with mbedtls_exit( 0 ) call.
x509/crl_app.c - left baremetal log but with mbedtls_exit( 0 ) call.
x509/cert_app.c - left baremetal log but with mbedtls_exit( 0 ) call.
ssl/ssl_mail_client.c - left baremetal log but with mbedtls_exit( 0 ) call.
ssl/ssl_pthread_server.c - left baremetal log but with mbedtls_exit( 0 ) call.
ssl/ssl_fork_server.c - left baremetal log but with mbedtls_exit( 0 ) call.
ssl_client1.c - line 54 - left baremetal log but with mbedtls_exit( 0 ) call.
ssl_client2.c - line 54 - left baremetal log but with mbedtls_exit( 0 ) call.
- line 132 - new options of both branches added.
- skip close notify handled as in 2.16.6, but with `ssl` instead of `&ssl`.
- Merged the 2.16.6 usage split with additional baremetal usages.
- Merged options from baremetal and 2.16.6.
ssl_server.c - left baremetal log but with mbedtls_exit( 0 ) call.
ssl_server2.c - Merged the 2.16.6 usage split with additional baremetal usages.
config.pl - fixed missing defines from the documentation, removed duplicates,
and reorganised so that the documentation and excluded list
are ordered in the same way.
test_suite_x509parse.data - only added the two new pathlen tests.
x509_crt.c - change the return code by removing
MBEDTLS_ERR_X509_INVALID_EXTENSIONS, since it's added by
x509_crt_frame_parse_ext not by an "or", but by "+=".
Changelog - Assigned all entries to appropriate sections.
ssl-opt.sh - line 8263 - merged options.
- removed lines 1165 - 1176 - there was a duplicate test, probably
an artifact of previous merges.
check-files.py - sticked to old formatting.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
This reverts commit 7550e857bf, reversing
changes made to d0c2575324.
stat() will never return S_IFLNK as the file type, as stat()
explicitly follows symlinks.
Fixes#3005.
Goals:
* Build with common compilers with common options, so that we don't
miss a (potentially useful) warning only triggered with certain
build options.
* A previous commit removed -O0 test jobs, leaving only the one with
-m32. We have inline assembly that is disabled with -O0, falling
back to generic C code. This commit restores a test that runs the
generic C code on a 64-bit platform.
If Y was constructed through functions in this module, then Y->n == 0
iff Y->p == NULL. However we do not prevent filling mpi structures
manually, and zero may be represented with n=0 and p a valid pointer.
Most of the code can cope with such a representation, but for the
source of mbedtls_mpi_copy, this would cause an integer underflow.
Changing the test for zero from Y->p==NULL to Y->n==0 causes this case
to work at no extra cost.
The splitting of this test into two versions depending on whether SHA-1 was
allowed by the server was a mistake in
5d2511c4d4 - the test has nothing to do with
SHA-1 in the first place, as the server doesn't request a certificate from
the client so it doesn't matter if the server accepts SHA-1 or not.
While the whole script makes (often implicit) assumptions about the version of
GnuTLS used, generally speaking it should work out of the box with the version
packaged on our reference testing platform, which is Ubuntu 16.04 so far.
With the update from Jan 8 2020 (3.4.10-4ubuntu1.6), the patches for rejecting
SHA-1 in certificate signatures were backported, so we should avoid presenting
SHA-1 signed certificates to a GnuTLS peer in ssl-opt.sh.
When mbedtls_x509_crt_parse_path() checks each object in the supplied path, it only processes regular files. This change makes it also accept a symlink to a file. Fixes#3005.
This was observed to be a problem on Fedora/CentOS/RHEL systems, where the ca-bundle in the default location is actually a symlink.
The functions mbedtls_ctr_drbg_random() and
mbedtls_ctr_drbg_random_with_add() could return 0 if an AES function
failed. This could only happen with alternative AES
implementations (the built-in implementation of the AES functions
involved never fail), typically due to a failure in a hardware
accelerator.
Bug reported and fix proposed by Johan Uppman Bruce and Christoffer
Lauri, Sectra.
None of the test cases in tests_suite_memory_buffer_alloc actually
need MBEDTLS_MEMORY_DEBUG. Some have additional checks when
MBEDTLS_MEMORY_DEBUG but all are useful even without it. So enable
them all and #ifdef out the parts that require DEBUG.
The test case "Memory buffer small buffer" emits a message
"FATAL: verification of first header failed". In this test case, it's
actually expected, but it looks weird to see this message from a
passing test. Add a comment that states this explicitly, and modify
the test description to indicate that the failure is expected, and
change the test function name to be more accurate.
Fix#309
This issue has been reported by Tuba Yavuz, Farhaan Fowze, Ken (Yihang) Bai,
Grant Hernandez, and Kevin Butler (University of Florida) and
Dave Tian (Purdue University).
In AES encrypt and decrypt some variables were left on the stack. The value
of these variables can be used to recover the last round key. To follow best
practice and to limit the impact of buffer overread vulnerabilities (like
Heartbleed) we need to zeroize them before exiting the function.
The corner case tests were designed for 32 and 64 bit limbs
independently and performed only on the target platform. On the other
platform they are not corner cases anymore, but we can still exercise
them.
The corner case tests were designed for 64 bit limbs and failed on 32
bit platforms because the numbers in the test ended up being stored in a
different number of limbs and the function (correctly) returnd an error
upon receiving them.
In the case of *ret we might need to preserve a 0 value throughout the
loop and therefore we need an extra condition to protect it from being
overwritten.
The value of done is always 1 after *ret has been set and does not need
to be protected from overwriting. Therefore in this case the extra
condition can be removed.
The code relied on the assumptions that CHAR_BIT is 8 and that unsigned
does not have padding bits.
In the Bignum module we already assume that the sign of an MPI is either
-1 or 1. Using this, we eliminate the above mentioned dependency.
The signature of mbedtls_mpi_cmp_mpi_ct() meant to support using it in
place of mbedtls_mpi_cmp_mpi(). This meant full comparison functionality
and a signed result.
To make the function more universal and friendly to constant time
coding, we change the result type to unsigned. Theoretically, we could
encode the comparison result in an unsigned value, but it would be less
intuitive.
Therefore we won't be able to represent the result as unsigned anymore
and the functionality will be constrained to checking if the first
operand is less than the second. This is sufficient to support the
current use case and to check any relationship between MPIs.
The only drawback is that we need to call the function twice when
checking for equality, but this can be optimised later if an when it is
needed.
Multiplication is known to have measurable timing variations based on
the operands. For example it typically is much faster if one of the
operands is zero. Remove them from constant time code.
You can't reuse a CTR_DRBG context without free()ing it and
re-init()ing it. This generally happened to work, but was never
guaranteed. It could have failed with alternative implementations of
the AES module because mbedtls_ctr_drbg_seed() calls
mbedtls_aes_init() on a context which is already initialized if
mbedtls_ctr_drbg_seed() hasn't been called before, plausibly causing a
memory leak.
Calling free() and seed() with no intervening init fails when
MBEDTLS_THREADING_C is enabled and all-bits-zero is not a valid mutex
representation.
You can't reuse a CTR_DRBG context without free()ing it and
re-init()ing. This generally happened to work, but was never
guaranteed. It could have failed with alternative implementations of
the AES module because mbedtls_ctr_drbg_seed() calls
mbedtls_aes_init() on a context which is already initialized if
mbedtls_ctr_drbg_seed() hasn't been called before, plausibly causing a
memory leak. Calling free() and seed() with no intervening init fails
when MBEDTLS_THREADING_C is enabled and all-bits-zero is not a valid
mutex representation. So add the missing free() and init().
The blinding applied to the scalar before modular inversion is
inadequate. Bignum is not constant time/constant trace, side channel
attacks can retrieve the blinded value, factor it (it is smaller than
RSA keys and not guaranteed to have only large prime factors). Then the
key can be recovered by brute force.
Reducing the blinded value makes factoring useless because the adversary
can only recover pk*t+z*N instead of pk*t.
mbedtls_ctr_drbg_seed() always set the entropy length to the default,
so a call to mbedtls_ctr_drbg_set_entropy_len() before seed() had no
effect. Change this to the more intuitive behavior that
set_entropy_len() sets the entropy length and seed() respects that and
only uses the default entropy length if there was no call to
set_entropy_len().
The former test-only function mbedtls_ctr_drbg_seed_entropy_len() is
no longer used, but keep it for strict ABI compatibility.
Move the definitions of mbedtls_ctr_drbg_seed_entropy_len() and
mbedtls_ctr_drbg_seed() to after they are used. This makes the code
easier to read and to maintain.
mbedtls_hmac_drbg_seed() always set the entropy length to the default,
so a call to mbedtls_hmac_drbg_set_entropy_len() before seed() had no
effect. Change this to the more intuitive behavior that
set_entropy_len() sets the entropy length and seed() respects that and
only uses the default entropy length if there was no call to
set_entropy_len().
When running 'make test' with GNU make, if a test suite program
displays "PASSED", this was automatically counted as a pass. This
would in particular count as passing:
* A test suite with the substring "PASSED" in a test description.
* A test suite where all the test cases succeeded, but the final
cleanup failed, in particular if a sanitizer reported a memory leak.
Use the test executable's return status instead to determine whether
the test suite passed. It's always 0 on PASSED unless the executable's
cleanup code fails, and it's never 0 on any failure.
FixARMmbed/mbed-crypto#303
Some sanitizers default to displaying an error message and recovering.
This could result in a test being recorded as passing despite a
complaint from the sanitizer. Turn off sanitizer recovery to avoid
this risk.
The documentation of HMAC_DRBG erroneously claimed that
mbedtls_hmac_drbg_set_entropy_len() had an impact on the initial
seeding. This is in fact not the case: mbedtls_hmac_drbg_seed() forces
the entropy length to its chosen value. Fix the documentation.
The documentation of CTR_DRBG erroneously claimed that
mbedtls_ctr_drbg_set_entropy_len() had an impact on the initial
seeding. This is in fact not the case: mbedtls_ctr_drbg_seed() forces
the initial seeding to grab MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes of
entropy. Fix the documentation and rewrite the discussion of the
entropy length and the security strength accordingly.
Explain how MBEDTLS_CTR_DRBG_ENTROPY_LEN is set next to the security
strength statement, rather than giving a partial explanation (current
setting only) in the documentation of MBEDTLS_CTR_DRBG_ENTROPY_LEN.
NIST and many other sources call it a "personalization string", and
certainly not "device-specific identifiers" which is actually somewhat
misleading since this is just one of many things that might go into a
personalization string.
Improve the formatting and writing of the documentation based on what
had been done for CTR_DRBG.
Document the maximum size and nullability of some buffer parameters.
Exercise the library functions with calloc returning NULL for a size
of 0. Make this a separate job with UBSan (and ASan) to detect
places where we try to dereference the result of calloc(0) or to do
things like
buf = calloc(size, 1);
if (buf == NULL && size != 0) return INSUFFICIENT_MEMORY;
memcpy(buf, source, size);
which has undefined behavior when buf is NULL at the memcpy call even
if size is 0.
This is needed because other test components jobs either use the system
malloc which returns non-NULL on Linux and FreeBSD, or the
memory_buffer_alloc malloc which returns NULL but does not give as
useful feedback with ASan (because the whole heap is a single C
object).
Add a very basic test of calloc to the selftest program. The selftest
program acts in its capacity as a platform compatibility checker rather
than in its capacity as a test of the library.
The main objective is to report whether calloc returns NULL for a size
of 0. Also observe whether a free/alloc sequence returns the address
that was just freed and whether a size overflow is properly detected.
This is a documentation-only change, but one that users who care about
NIST compliance may be interested in, to review if they're using the
module in a compliant way.
Document that a derivation function is used.
Document the security strength of the DRBG depending on the
compile-time configuration and how it is set up. In particular,
document how the nonce specified in SP 800-90A is set.
Mention how to link the ctr_drbg module with the entropy module.
* State explicit whether several numbers are in bits or bytes.
* Clarify whether buffer pointer parameters can be NULL.
* Explain the value of constants that are dependent on the configuration.
ssl_decompress_buf() was operating on data from the ssl context, but called at
a point where this data is actually in the rec structure. Call it later so
that the data is back to the ssl structure.
Signed-off-by: Simon Butcher <simon.butcher@arm.com>
There is a 50% performance drop in the SCA_CM enabled encrypt and
decrypt functions. Therefore use the older version of encrypt/decypt
functions when SCA_CM is disabled.
-Do not reuse any part of randomized number, use separate byte for
each purpose.
-Combine some separate loops together to get rid of gap between them
-Extend usage of flow_control
* upstream/pr/2945:
Rename macro MBEDTLS_MAX_RAND_DELAY
Update signature of mbedtls_platform_random_delay
Replace mbedtls_platform_enforce_volatile_reads 2
Replace mbedtls_platform_enforce_volatile_reads
Add more variation to random delay countermeasure
Add random delay to enforce_volatile_reads
Update comments of mbedtls_platform_random_delay
Follow Mbed TLS coding style
Add random delay function to platform_utils
When reading the input, buffer will be initialised with random data
and the reading will start from a random offset. When writing the data,
the output will be initialised with random data and the writing will start
from a random offset.
When reading the input, the buffer will be initialised with random data
and the reading will start from a random offset. When writing the data,
the output will be initialised with random data and the writing will
start from a random offset.
Add more variation to the random delay function by xor:ing two
variables. It is not enough to increment just a counter to create a
delay as it will be visible as uniform delay that can be easily
removed from the trace by analysis.
The flag is used for tracking if the premaster has
been succesfully generated. Note that when resuming
a session, the flag should not be used when trying to
notice if all the key generation/derivation has been done.
Default flow assumes failure causes multiple issues with
compatibility tests when the return value is initialised
with error value in ssl_in_server_key_exchange_parse.
The function would need a significant change in structure for this.
The verification could be skipped in server, changed the default flow
so that the handshake status is ever updated if the verify
succeeds, and that is checked twice.
The MBEDTLS_ERR_SSL_WANT_READ and MBEDTLS_ERR_SSL_WANT_WRITE are
errors that can be ignored, so increase the hamming distance between
them and the non-ignorable errors and keep still some distance from
a success case. This mitigates an attack where single bit-flipping could
change a non-ignorable error to being an ignorable one.
Check that the encryption has been done for the outbut buffer.
This is to ensure that glitching out the encryption doesn't
result as a unecrypted buffer to be sent.
This is to enable hardening the security when changing
states in state machine so that the state cannot be changed by bit flipping.
The later commit changes the enumerations so that the states have large
hamming distance in between them to prevent this kind of attack.
Duplicating the g_rng_function variable in ecc_dsa.c means it's not the same
as set in ecc.c, resulting if no randomisation here. The proper way to access
the RNG function from outside ecc.c is uECC_get_rng(), so use that.
This is a side-port of upstream commit
87d74dd8d64a99aaa188961fe763d0841c5abfef
I've verified that there are no other occurrences (the duplication of
g_rng_function in ecc_dh.c had already been removed earlier when centralising
projective coordinate randomisation to mult_safer()).
-Replace usage of rand() with mbedtls_platform_random_in_range()
-Prevent for-ever loop by hardcoding SCA countermeasure position in
case of used random function is always returning constant number.
-Use separate control bytes for start and final round to get them
randomized separately.
-Remove struct name.
-Fix comments and follow Mbed TLS coding style.
SCA CM implementation caused AES performance drop. For example
AES-CCM-128 calculation speed was dropped from 240 KB/s to 111 KB/s.
(-54%), Similarily AES-CBC-128 calculation speed was dropped from
536 KB/s to 237 KB/s (-56%).
Use functions instead of macros to reduce code indirections and
therefore increase performance. Now the performance is 163 KB/s for
AES-CCM-128 (-32%) and 348 KB/s for AES-CBC-128 (-35%).
When SCA countermeasures are activated the performance is as follows:
122 KB/s for AES-CCM-128 (-49%) and 258 KB/s for AES-CBC-128 (-52%)
compared to the original AES implementation.
Use control bytes to instruct AES calculation rounds. Each
calculation round has a control byte that indicates what data
(real/fake) is used and if any offset is required for AES data
positions.
First and last AES calculation round are calculated with SCA CM data
included. The calculation order is randomized by the control bytes.
Calculations between the first and last rounds contains 3 SCA CMs
in randomized positions.
- Add configuration for AES_SCA_COUNTERMEASURES to config.h. By
default the feature is disabled.
- Add AES_SCA_COUNTERMEASURES configuration check to check_config.h
- Add AES_SCA_COUNTERMEASURES test to all.sh
- 3 additional dummy AES rounds calculated with random data for each
AES encryption/decryption
- additional rounds can be occur in any point in sequence of rounds
Found by the IAR compiler.
While at it, make 'diff' non-volatile in uECC_check_curve_integrity(), as
there is no good reason to make it volatile, and making it volatile only
increases the code size and the burden of defining access ordering.
- MSVC doesn't like -1u
- We need to include platform.h for MBEDTLS_ERR_PLATFORM_FAULT_DETECTED - in
some configurations it was already included indirectly, but not in all
configurations, so better include it directly.
This commit first changes the return convention of EccPoint_mult_safer() so
that it properly reports when faults are detected. Then all functions that
call it need to be changed to (1) follow the same return convention and (2)
properly propagate UECC_FAULT_DETECTED when it occurs.
Here's the reverse call graph from EccPoint_mult_safer() to the rest of the
library (where return values are translated to the MBEDTLS_ERR_ space) and test
functions (where expected return values are asserted explicitly).
EccPoint_mult_safer()
EccPoint_compute_public_key()
uECC_compute_public_key()
pkparse.c
tests/suites/test_suite_pkparse.function
uECC_make_key_with_d()
uECC_make_key()
ssl_cli.c
ssl_srv.c
tests/suites/test_suite_pk.function
tests/suites/test_suite_tinycrypt.function
uECC_shared_secret()
ssl_tls.c
tests/suites/test_suite_tinycrypt.function
uECC_sign_with_k()
uECC_sign()
pk.c
tests/suites/test_suite_tinycrypt.function
Note: in uECC_sign_with_k() a test for uECC_vli_isZero(p) is suppressed
because it is redundant with a more thorough test (point validity) done at the
end of EccPoint_mult_safer(). This redundancy was introduced in a previous
commit but not noticed earlier.
We don't really need a secure hash for that, something like CRC32 would
probably be enough - but we have SHA-256 handy, not CRC32, so use that for the
sake of simplicity.
By semi-internal I mean functions that are only public because they're used in
more than once compilation unit in the library (for example in ecc.c and
ecc_dsa.c) but should not really be part of the public-facing API.
Same motivation as for the other parameters. This is the last one, making the
curve structure empty, so it's left with a dummy parameter for legal reasons.
-Add flow monitor, loop integrity check and variable doubling to
harden mbedtls_hmac_drbg_update_ret.
-Use longer hamming distance for nonce usage in hmac_drbg_reseed_core
-Return actual value instead of success in mbedtls_hmac_drbg_seed and
mbedtls_hmac_drbg_seed_buf
-Check illegal condition in hmac_drbg_reseed_core.
-Double buf/buf_len variables in mbedtls_hmac_drbg_random_with_add
-Add more hamming distance to MBEDTLS_HMAC_DRBG_PR_ON/OFF
Added an additional Makefile option of 'TINYCRYPT_BUILD' to exclude the
TinyCrypt source files from the build. This allows some tests to exclude those
files as and when necessary.
Specifically this includes in all.sh the test
'component_build_arm_none_eabi_gcc_no_64bit_multiplication' which was failing as
64bit cannot be disabled in TinyCrypt, and check-names.sh as TinyCrypt obviously
does not conform to Mbed TLS naming conventions.
This commit removes from the TinyCrypt header and source code files, the
configuration condition on MBEDTLS_USE_TINYCRYPT to include the file
contents.
This is to allow use of the library by the Factory Tool without enabling
MBEDTLS_USE_TINYCRYPT, and also removes a modification we've made to make the
code closer to the upstream TinyCrypt making it easier to maintain.
Validating the input is always a good idea. Validating the output protects
against some fault injections that would make the result invalid.
Note: valid_point() implies that the point is not zero.
Adding validation to mult_safer() makes it redundant in
compute_shared_secret().
This will make easier to add future counter-measures in a single place.
In practice this change means that:
- compute_public_key() now uses projective coordinate randomisation, which it
should as this is a protection against Template Attacks for example.
- mult_safer() now checks that the result is not the point at infinity, which
it can as the result is indeed never expected to be that
In the previous version, it was enough for the attacker to glitch the
top-level 'if' to skip the entire block. We want two independent blocks here,
so that an attacker can only succeed with two successive glitches.
Before this commit, if a certificate only had one issue (for example, if the
"untrusted" bit was the only set in flags), an attacker that could flip this
single bit between the moment it's set and the moment flags are checked before
returning from mbedtls_x509_crt_verify() could make the entire verification
routine appear to succeed (return 0 with no bit set in flags).
Avoid that by making sure that flags always has either 0 or at least 9 bits
set during the execution of the function. However, to preserve the API, clear
the 8 extra bits before returning. This doesn't open the door to other
attacks, as fortunately the API already had redundancy: either both flags and
the return value are 0, or flags has bits set and the return value is non-zero
with at least 16 bits set (assuming 32-bit 2-complement ints).
If signature_is_good is 0 (invalid) of 1 (valid), then it's all too easy for
an active physical attacker to turn invalid into valid by flipping a single
bit in RAM, on the bus or in a CPU register.
Use a special value to represent "valid" that can't easily be reached by
flipping a few bits.
x509_crt_check_signature() directly returns the return value of
pk_verify_xxx() without looking at it, so nothing to do here. But its caller
compares the value to 0, which ought to be double-checked.
Inspection of the generated assembly showed that before this commit, armcc 5
was optimizing away the successive reads to the volatile local variable that's
used for double-checks. Inspection also reveals that inserting a call to an
external function is enough to prevent it from doing that.
The tested versions of ARM-GCC, Clang and Armcc 6 (aka armclang) all keep the
double read, with our without a call to an external function in the middle.
The inserted function can also be changed to insert a random delay if
desired in the future, as it is appropriately places between the reads.
This can be used by Mbed TLS functions in any module to signal that a fault
attack is likely happening, so this can be appropriately handled by the
application (report, fall back to safer mode or even halt, etc.)
This hardens against attacks that glitch the conditional branch by making it
necessary for the attacker to inject two consecutive faults instead of one. If
desired, we could insert a random delay in order to further protect against
double-glitch attacks.
Also, when a single glitch is detected we report it.
Previously it was returning 0 or 1, so flipping a single bit in the return
value reversed its meaning. Now it's returning the diff itself.
This is safe because in the two places it's used (signature verification and
point validation), invalid values will have a large number of bits differing
from the expected value, so diff will have a large Hamming weight.
An alternative would be to return for example -!(diff == 0), but the
comparison itself is prone to attacks (glitching the appropriate flag in the
CPU flags register, or the conditional branch if the comparison uses one). So
we'd need to protect the comparison, and it's simpler to just skip it and
return diff itself.
This is a first step in protecting against fault injection attacks: the
attacker can no longer change failure into success by flipping a single bit.
Additional steps are needed to prevent other attacks (instruction skip etc)
and will be the object of future commits.
The return value of uECC_vli_equal() should be protected as well, which will
be done in a future commit as well.
Currently functions that may return success or failure tend to do so by
returning 0 or 1. If an active physical attacker can flip a bit in memory or
registers at the right time, they may easily change a failure value into a
success value, with potentially catastrophic security consequences.
As typical attackers can only flip a few bits, an element of protection
against such attacks is to ensure a sufficient Hamming distance between
failure values and the success value. This commit introduces such values,
which will put to use in critical functions in future commits.
In addition to SUCCESS and FAILURE, a third value ATTACK_DETECTED is
introduced, which can be used later when suspicious-looking events are noticed
(static data changed when it shouldn't, double condition checking returning
inconsistent results, etc.).
Values are chosen so that Hamming distances are large, and that no value is
the complement of another, in order to avoid unwanted compiler optimisations.
Note: the error values used by Mbed TLS are already safe (assuming 32-bit
integers) as they are of the form -x with x in the range [1, 2^15) so their
Hamming distance with the success value (0) is at least 17, so it's hard for
an attacker to turn an error value into the success value (or vice-versa).
This is a temporary work-around for an integration issue.
A future task will re-integrate randomness into these functions are their
entire point is to be randomized; this is really just temporary.
This avoids the need for each calling site to manually regularize the scalar
and randomize coordinates, which makes for simpler safe use and saves 50 bytes
of code size in the library.
Even though this is type name is purely internal to a single C file, let's
reduce the potential for clashes with other wait state types which might be
added elsewhere in the library and become visible here (for example through
platform_util.h).
Previous size was 3584 bytes which is not acceptable on constrained systems
(especially on the stack). This was a misguided attempt at minimizing the
number of calls to the RNG function in order to minimize impact on
performance, but clearly this does not justify using that much RAM and a
compromise had to be found.
While at it, loose the 'curve' argument in internal randomized functions, for
the same reasons we lost 'num_words' in uECC_vli_mult_rnd(): we only have one
curve so we don't need this, and hardcoding it saves a bit of code size and
speed, which is welcome to slightly reduce the impact of the counter-measure
on both of them.
This is a counter-measure to make horizontal attacks harder. Horizontal
attacks work with a single trace by noticing when intermediate computations
within that trace happen on the same operands.
We'll try to make that harder for an attacker to achieve that by introducing
random delays based on extra computation and extra random accesses to input in
the multi-precision multiplication (which is the dominant operation and the target of
horizontal attacks known so far). This should make it hard for the attacker to
compare two multiplications.
This first commit introduces the new function for multiplication with random
delay - future commits will ensure it is used all the way up to the top-level
scalar multiplication routine.
Why: this protects against potential side-channels attacks. This
counter-measure is for example effective against Template SPA. Also, the
bignum arithmetic as implemented in TinyCrypt isn't entirely regular, which
could in principle be exploited by an attacker; randomizing the coordinates
makes this less likely to happen.
Randomizing projective coordinates is also a well-known countermeasure to DPA.
In the context of the scalar multiplication in ECDSA, DPA isn't a concern
since it requires multiple measurements with various base points and the same
scalar, and the scalar mult in ECDSA is the opposite: the base point's always
the same and the scalar is always unique. But we want protection against the
other attacks as well.
How: we use the same code fragment as in uECC_shared_secret in ecc_dh.c,
adapted as follows: (1) replace p2 with k2 as that's how it's called in this
function; (2) adjust how errors are handled.
The code might not be immediately clear so here are a few more details:
regularize_k() takes two arrays as outputs, and the return value says which one
should be passed to ECCPoint_mult(). The other one is free for us to re-use to
generate a random number to be used as the initial Z value for randomizing
coordinates (otherwise the initial Z value is 1), thus avoiding the use of an
extra stack buffer.
The certificate has a corrupted public key and signature.
Generating it through Makefile isn't trivial and since it is
a corrupted certificate, that shouldn't be accepted, there
shouldn't be a need to generate it again anyway.
Only add test when both are enforcing. This is configured in baremetal.h
and is checked in the check_cmdline_compat, would render other cases
with baremetal.h to skipped.
Record checking fails if mbedtls_ssl_check_record() is called with
external buffer. Received record sequence number is available in the
incoming record but it is not available in the ssl contexts `in_ctr`-
variable that is used when decoding the sequence number.
To fix the problem, temporarily update ssl context `in_ctr` to
point to the received record header and restore value later.
Override define MBEDTLS_ENTROPY_MAX_SOURCES from 1 to 3 in baremetal_test.h
mbedtls_entropy_init adds 2 sources already so max must be 3 so that
one source can be added with mbedtls_entropy_add_source.
-Add config option for AES encyption only to config.h. Feature is
disabled by default.
-Enable AES encrypt only feature in baremetal.h configuration
-Remove AES encypt only feature from full config
- Unset MBEDTLS_PADLOCK_C in aes_only_128_bit_keys test to get RAM
optimised version tested
- Use compiler flag "-O1" instead of "-Wall -Wextra" to see warnings
Do not reserve additionl space for mbedtls_aes_context if config
option AES_ONLY_128_BIT_KEY_LENGTH is used and PADLOCK_C is not used.
This reduces RAM usage by 96 bytes.
In baremetal configuration reserve space for 10 128-bit keys in order
to save 112 bytes of heap.
- Do not include MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH to full config
as it requires also MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
- Update check_config to check availability of flags:
MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH
MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
Ultimately, mbedtls_hardware_poll() is going to be provided by the
OS/environment when running on target. But for on-host programs and tests, we
need to define (a fake version) in each program that we want to be able to
link.
A previous commit took care of ssl_client2 and ssl_server2. But if we want to
be able to compile all programs, we need to modify each of them. This doesn't
seem useful, so instead let's just build the programs we need for testing -
this means only udp_proxy needs fixing in addition to what's already done.
This issue went unnoticed in the PR that introduced the new all.sh component,
because at that time the platform_memxxx() functions were not actually used in
the library (nor in programs), so the linker could live with
mbedtls_hardware_poll() not being defined, as it wasn't called anywhere. This
changed when we started using the new platform_memxxx() functions in the
library.
- out_ctr is public because it's transmited over the wire in DTLS (and in TLS
it can be inferred by a passive network attacker just by counting records).
- handshake mask is not a secret because it can be inferred by a passive
network attacker just logging record sequence number seen so far.
This commits reverts to plain memset() for cases like:
some_type foo;
memset( &foo, 0, sizeof( foo ) );
(Sometimes there is code between declaration in memset(), but it doesn't
matter as long as it doesn't touch foo.)
The reasoning is the same as in the previous commit: the stack shouldn't
contain sensitive data as we carefully wipe it after use.
We call xxx_init() on a structure when it has been freshly allocated (on the
stack or heap).
At this point it contains random-looking data none of which should be
sensitive, as all sensitive data is wiped using mbedtls_platform_zeroize()
when we're done using it and the memory area is going to be reclaimed (by
exiting the function or free()ing the buffer).
Add it in all files that use mbedtls_plaform_memset() but didn't already
include platfom_util.h.
In some configurations it just happened to work, either because it was
included indirectly or because the part of the code that used that function
was disabled, but it some configurations it broke, so let's fix it properly.
Steps:
1. sed -i 's/\bmemset(\([^)]\)/mbedtls_platform_memset(\1/g' library/*.c tinycrypt/*.c include/mbedtls/*.h scripts/data_files/*.fmt
2. Manually edit library/platform_util.c to revert to memset() in the
implementations of mbedtls_platform_memset() and mbedtls_platform_memcpy()
3. egrep -n '\<memset\>' library/*.c include/mbedtls/*.h tinycrypt/*.c
The remaining occurrences are in three categories:
a. From point 2 above.
b. In comments.
c. In the initialisation of memset_func, to be changed in a future commit.
This commit modifies the example programs ssl_client2 and ssl_server2
to allocate various structures on the heap instead of the stack. This
allows more fine-grained memory usage tracking via valgrind massif.
* mbedtls-2.16: (25 commits)
Fix compilation error
Add const to variable
Fix endianity issue when reading uint32
Increase test suite timeout
Reduce stack usage of test_suite_pkcs1_v15
Reduce stack usage of test_suite_pkcs1_v21
Reduce stack usage of test_suite_rsa
Reduce stack usage of test_suite_pk
Enable MBEDTLS_MEMORY_DEBUG in memory buffer alloc test in all.sh
Remove unnecessary memory buffer alloc and memory backtrace unsets
Disable DTLS proxy tests for MEMORY_BUFFER_ALLOC test
all.sh: restructure memory allocator tests
Add missing dependency in memory buffer alloc set in all.sh
Don't set MBEDTLS_MEMORY_DEBUG through `scripts/config.pl full`
Add cfg dep MBEDTLS_MEMORY_DEBUG->MBEDTLS_MEMORY_BUFFER_ALLOC_C
Add all.sh run with full config and ASan enabled
Add all.sh run with MBEDTLS_MEMORY_BUFFER_ALLOC_C enabled
Update documentation of exceptions for `config.pl full`
Adapt all.sh to removal of buffer allocator from full config
Disable memory buffer allocator in full config
...
There is a static dependency in the test system for
this file. To prevent the issue from happening, move
the definition to the end of file so that the last
return in the main remains in the same line.
Use MBEDTLS_ENTROPY_HARDWARE_ALT instead of a new global RNG
flag. When this flag is enabled, the platform provides the RNG.
When running unit tests, rnd_std_rand should be used by overriding
the mbedtls_hardware_poll.
As replacements of standard library functions, they should have the same
prototype, including return type.
While it doesn't usually matter when used directly, it does when the address
of the function is taken, as done with memset_func, used for implementing
mbedtls_platform_zeroize().
Warnings are treated as errors in Mbed TLS test. An error
"ssl_parse_client_hello_v2’ defined but not used" can occur in some
specific configurations and therefore tests will break.
Use similar flags for static function "ssl_parse_client_hello_v2" as
what is used when calling the function to prevent the compilation
warning/error.
query_opt is used to read Mbed TLS configuration values instead of
config.pl script. Now MBEDTLS_SSL_MAX_CONTENT_LEN value is correctly
read and some tests needs to be removed from the test set when value
of MBEDTLS_SSL_MAX_CONTENT_LEN is too small for the test.
-Add comments to Makefiles about test env auto-detection
-Fix indentation
-Remove parent folder from include dirs
-Do not use environment variable for defining config file because
env variable usage is not fully implemented
-Revert changes to config.pl
This commit reimplements the helper functions
- requires_config_enabled
- requires_config_disabled
in ssl-opt.sh in terms of the programs/test/query_config
programs which allows to query the configuration in which
Mbed TLS was built.
This removes the dependency of ssl-opt.sh from the config
that was used to build the library.
This makes a mbedtls_pk_context memory-wise equivalent to a
mbedtls_uecc_keypair and removes a dynamic allocation, making the PK layer
zero-cost in terms of memory when PK_SINGLE_TYPE is enabled.
In very reduced configurations, we don't want the overhead of maintaining a
bool just to remember if the context is valid and checking that bit at every
point of entry.
Note: so far this validity bit also served as a proxy to ensure that pk_ctx
was valid (currently this is a pointer to a dynamically-allocated buffer). In
the next series of commits, this will be changed to a statically-allocated
buffer, so there will be no question about its validity.
In the end (after this commit and the next series), a pk_context_t will be
(memory-wise) just the same as a mbedtls_uecc_keypair when SINGLE_TYPE is
enabled - meaning the PK layer will have zero memory overhead in that case.
So far, with MBEDTLS_SSL_KEEP_PEER_CERTIFICATE disabled, the SSL module relied
on a undocumented feature of the PK module: that you can distinguish between
contexts that have been setup and context that haven't. This feature is going
to go away in the case of PK_SINGLE_TYPE, as we'll soon (as in: the next
commit does that) no longer be storing the (now two-valued) pk_info member.
Note even with this change, we could still distinguish if the context has been
set up by look if pk_ctx is NULL or not, but this is also going away in the
near future (a few more commits down the road), so not a good option either.
This is the first in a series of commit aimed at removing the pk_info
structures when we're building with MBEDTLS_PK_SINGLE_TYPE enabled.
Introducing this abstraction allows us to later make it a two-valued type
(valid, invalid) instead, which is much lighter.
For optional functions, we introduce an extra macro to tell if the function is
omitted. As the C preprocessor doesn't directly support comparing strings,
testing if the _FUNC macro is defined to NULL isn't obvious. One could
probably play tricks to avoid the need for _OMIT macros, but the small amount
of (entirely local) duplication here is probably a lesser evil than extra
preprocessor complexity.
We want public functions to resolve to the internal wrappers at compile-time.
For this we need the wrappers to be visible from where the public functions
are defined. A simple declaration is not enough if we want the compiler to be
able to inline the wrapper and eliminate function overhead.
This commit just copies verbatim the contents of pk_wrap.c into pk.c. The next
commit will clean up the result (redundant includes etc.).
No effect for now, just declaring it here, implemented in subsequent commits.
The option requires MBEDTLS_USE_TINYCRYPT and is incompatible with
MBEDTLS_PK_RSA_ALT_SUPPORT and MBEDTLS_RSA_C.
Currently users (including the X.509 and SSL libraries) assume that if both PK
and RSA are enabled, then RSA is available through PK. If we allowed RSA to be
enabled together with PK_SINGLE_TYPE, we'd break that assumption. Going
through the code to find all place that rely on that assumption and fix them
would be cumbersome, and people who want PK_SINGLE_TYPE are unlikely to care
about RSA anyway, so let's just make them incompatible.
This is also consistent with what's done in the MD module: MD_SINGLE_HASH
requires that exactly one hash be enabled.
The programs assume that including "pk.h" brings up "bignum.h". When
MBEDTLS_USE_TINYCRYPT is enabled and MBEDTLS_RSA_C is disabled, that
assumption no longer holds. Fix that by explicitly including bignum.h from the
programs that need it.
This is a bug pre-existing to this PR, fixed here to enable the inclusion of a
test with a config that happens to reveal it.
This achieves two related goals:
1. Those members are now only accessed via the accessor function (except in
code paths that we don't care about: those guarded by
MBEDTLS_PK_RSA_ALT_SUPPORT or MBEDTLS_ECP_RESTARTABLE)
2. When we turn on compile-time dispatch, we don't obviously don't want to
keep a runtime NULL check.
For debug this requires changing the signature or the accessor function to
return int; this is done without changing the signature of the accessed
function.
1. Mark an RSA-alt-specific code path as such.
2. Move NULL check for wrapper function closer to the use of that function.
Those are in preparation of the next commit.
This is the first commit in a series aiming at implementing optional
compile-time dispatch when a single PK type is hardcoded. At the end of this
series, the functions introduced here will directly resolve to the correct
function at compile-time when this (to be created) option is enabled.
* baremetal: (78 commits)
Review corrections 6
Review corrections 5
Minor changes to tinycrypt README
Typos in the tinycrypt README
Addition of copyright statements to tinycrypt files
Add LICENSE and README for tinycrypt
Add SPDX lines to each imported TinyCrypt file
Review corrections 4
Review corrections 3
Review corrections 2
Review corrections
Update signature of BE conversion functions
Use function for 16/24/32-bit BE conversion
x509.c: Minor readability improvement
x509_crt.c: Indicate guarding condition in #else branch
X.509: Don't remove verify callback by default
Fix Doxygen warnings regarding removed verify cb+ctx parameters
ECC restart: Use optional verification mode in bad signature test
Re-implement verify chain if vrfy cbs are disabled
Add zero-cost abstraction layer for CRT verification chain
...
In previous merges, ChangeLog entries from the baremetal branch got mixed with
entries from the 2.16 branch, which resulted in a confusing and unhelpful log.
Restore some order by grouping all baremetal entries in their own section.
On the mbedtls-2.16 side, there was a change in commit
a7cfdad82e (PR r#503) in order to write
fixed-length private keys. It added a new helper function
pk_write_ec_private() for that.
On the baremetal side, there were changes in order to add a tinycrypt-based
implementation. It added a new helper function pk_write_ec_privkey() with two
implementations (with or without tinycrypt).
This commit keeps the function pk_write_ec_privkey() but changes its
implementation in the non-tinycrypt configuration in order to match the
implementation of pk_write_ec_private(), which is in turn removed it was only
used in that place.
The tinycrypt version of pk_write_ec_private() was already writing
constant-length private keys, so there is nothing to change here.
* mbedtls-2.16: (28 commits)
Bump version to Mbed TLS 2.16.3
Changelog entry
Check for zero length and NULL buffer pointer
ssl-opt.sh: wait for proxy to start before running the script further
Fix uninitialized variable in x509_crt
HMAC DRBG: Split entropy-gathering requests to reduce request sizes
Fix the license header of hkdf
Add a change log entry
Add a test for mlaformed ECJPAKE context
Fix handling of md failure
Add a test for signing content with a long ECDSA key
Add documentation notes about the required size of the signature buffers
Add missing MBEDTLS_ECP_C dependencies in check_config.h
Change size of preallocated buffer for pk_sign() calls
Adapt ChangeLog
Fix mpi_bigendian_to_host() on bigendian systems
Add ChangeLog entry for new function
Add ChangeLog entry
Correct deterministic ECDSA behavior
Add warning for alternative ECDSA implementations
...
This commit adds a LICENSE file and README file to tinycrypt, to help auditing
of the source code for licenses and also to indicate the origin of the work.
- Try to follow english grammar in function documentation
- Fix too long line
- Remove additional brackets
- Follow mbedtls coding style in for-statement
-Fix MSVC compiler warnings about size_t to uint32_t conversions by
updating GET/PUT functions signature to use size_t.
-Add type casts to functions calling GET/PUT conversions
-Remove additional space after return statement
This commit re-implements the previously introduced internal
verification chain API in the case where verification callbacks
are disabled. In this situation, it is not necessary to maintain
the list of individual certificates and flags comprising the
verification chain - instead, it suffices to just keep track
of the length and the total (=merged) flags.
When verifying an X.509 certificate, the current verification logic
maintains an instance of the internal mbedtls_x509_crt_verify_chain
structure representing the state of the verification process. This
instance references the list of certificates that comprise the chain
built so far together with their verification flags. This information
must be stored during verification because it's being passed to the
verification callback at the end of verification - if the user has
specified those.
If the user hasn't specified a verification callback, it is not
necessary to maintain the list of CRTs, and it is also not necessary
to maintain verification flags for each CRT individually, as they're
merged at the end of the verification process.
To allow a readable simplification of the code in case no verification
callbacks are used, this commit introduces a zero-cost abstraction layer
for the functionality that's required from the verification chain structure:
- init/reset
- add a new CRT to the chain
- get pointer to current CRT flags
- add flags to EE certificate
- get current chain length
- trigger callbacks and get final (merged) flags
This gives flexibility for re-implementing the verification chain
structure, e.g. in the case where no verification callbacks are
provided, and there's hence no need to store CRTs and flags
individually. This will be done in a later commit.
When MBEDTLS_MD_SINGLE_HASH is set, both the underlying digest context
and the HMAC data are embedded into the mbedtls_md_context; otherwise,
they're dynamically allocated and referenced from mbedtls_md_context.
When the HMAC data is embedded in mbedtls_md_context, it's unnecessary
to check whether mbedtls_md_context::hmac_ctx is NULL, because that's
never the case in defined behaviour, but the check has kept for
uniformity so far. However, contrary to the expectation that compilers
would silently remove this check as always false, ARMC6 complains about
it, breaking some tests in all.sh.
This commit fixes this by guarding checks for
mbedtls_md_context::hmac_ctx == NULL
by !MBEDTLS_MD_SINGLE_HASH.
When MBEDTLS_MD_SINGLE_HASH is set, the underlying digest's
context is embedded into mbedtls_md_context_t, which is
zeroized before the underlying digest's init() function
is called. For those digests where initialization is
zeroization, the init() call can therefore be omitted.
Similarly, when free()-ing an mbedtls_md_context_t, the
entire context is zeroized in the end, hence if the
underlying digest's free() function is zeroization,
it can be omitted.
Recall that in the default configuration, Mbed TLS provides access
digest implementations through two layers of indirection:
1) Call of MD API (e.g. mbedtls_md_update())
2) Call of function pointer from MD info structure
3) Actual digest implementation (e.g. mbedtls_sha256_update()).
Ideally, if only a single digest is enabled - say SHA-256 - then calling
mbedtls_md_update() should _directly_ jump to mbedtls_sha256_update(),
with both layers of indirection removed. So far, however, setting
MBEDTLS_MD_SINGLE_HASH will only remove the second - function pointer -
layer of indirection, while keeping the non-inlined stub implementations
of e.g. mbedtls_md_update() around.
This commit is a step towards allowing to define implementations of
the MD API as `static inline` in case we know that they are so small
that they should be defined in md.h and not in md.c.
In a nutshell, the approach is as follows: For an MD API function
mbedtls_md_xxx() that should be inlin-able, introduce its implementation
as a `static inline` wrapper `mbedtls_md_xxx_internal()` in md.h,
and then define mbedtls_md_xxx() either in md.h or in md.c, by just
calling mbedtls_md_xxx_internal().
Moving the implementations of those MD API functions that should be
inlinable to md.h requires the presence of both the MD info struct
and all specific digest wrapper functions in md.h, and this is what
this commit ensures, by moving them from md.c into a new internal
header file md_internal.h. Implementing the aforementioned wrappers for
those MD API that should be inlinable is left for subsequent commits.
ARMC5 appears to use the heuristic that as soon as a function's address
is taken, the function can no longer be removed from the resulting object
file (which is not necessarily true if all uses of the functions address
can be inlined).
Circumvent this lack of optimization by not returning function pointers.
This commit modifies check_config.h to check that precisely one
hash is enabled if MBEDTLS_MD_SINGLE_HASH is set.
This is not only a reasonable expectation, it is also necessary,
because test suites assume that if a digest is enabled, it is also
accessible through the MD abstraction layer.
With the removal of the MD handle from the MD context, it's a precondition
for any MD API outside of mbedtls_md_init() and mbedtls_md_setup() that
the MD context has been successfully setup by precisely those functions
beforehand, and hence must be bound to the single enabled valid MD handle.
This commit introduces the configuration option
MBEDTLS_MD_SINGLE_HASH
which can be used to hardcode support for a single digest algorithm
at compile-time, at the benefit of reduced code-size.
To use, it needs to be defined to evaluate to a macro of the form
MBEDTLS_MD_INFO_{DIGEST}, and macros MBEDTLS_MD_INFO_{DIGEST}_FIELD
must be defined, giving rise to the various aspects (name, type,
size, ...) of the chosen digest algorithm. MBEDTLS_MD_INFO_SHA256
provides an example, but other algorithms can be added if needed.
At the moment, the effect of using MBEDTLS_MD_SINGLE_HASH is that
the implementation of the MD API (e.g. mbedtls_md_update()) need no
longer to through the abstraction of the mbedtls_md_info structures
by calling their corresponding function pointers fields (akin to
virtual functions in C++), but the directly call the corresponding
core digest function (such as mbedtls_sha256_update()).
Therefore, MBEDTLS_MD_SINGLE_HASH so far removes the second layer
of indirection in the chain
User calls MD API -> MD API calls underlying digest impl'n
-> Core digest impl'n does the actual work,
but the first indirection remains, as the MD API remains untouched
and cannot yet be inlined. Studying to what extend inlining the
shortened MD API implementations would lead to further code-savings
is left for a later commit.
In builds enabling only a single MD digest, we want to be able to
implement the MD info getter functions by returning compile-time
constants matching the fields of the MD info structures used so far.
To avoid information duplication hardening maintainability, this
commit introduces the possibility of providing the various aspects
of a particular digest implementation by defining macros
MBEDTLS_MD_INFO_DIGEST_FIELD (e.g. MBEDTLS_MD_INFO_SHA256_SIZE)
and to generate the corresponding mbedtls_md_info instance from
this set of macros, via the new macro MBEDTLS_MD_INFO().
This way, we'll be able to switch between MD info based builds
and single-digest builds without information duplication.
This commit continues the introduction of the MD digest implementation
abstraction layer given by `mbedtls_md_handle_t` by adding getter
functions returning the various properties of an implementation
(e.g. name, digest type, digest size). For the existing implementation,
these are just structure field accesses; however, in configurations
hardcoding the choice of a fixed digest algorithm, we'll be able to
implement them as inline functions returning compile-time constants.
As has been previously done for ciphersuites, this commit introduces
a zero-cost abstraction layer around the type
mbedtls_md_info const *
whose valid values represent implementations of message digest algorithms.
Access to a particular digest implementation can be requested by name or
digest ID through the API mbedtls_md_info_from_xxx(), which either returns
a valid implementation or NULL, representing failure.
This commit replaces such uses of `mbedtls_md_info const *` by an abstract
type `mbedtls_md_handle_t` whose valid values represent digest implementations,
and which has a designated invalid value MBEDTLS_MD_INVALID_HANDLE.
The purpose of this abstraction layer is to pave the way for builds which
support precisely one digest algorithm. In this case, mbedtls_md_handle_t
can be implemented as a two-valued type, with one value representing the
invalid handle, and the unique valid value representing the unique enabled
digest.
Cookies are fully opaque so we can change the hash used at any time, it's not
part of the API.
The cookie module handles truncation, so it's simpler to always use SHA-256
rather than check if SHA-224 is available.
Add a basic unit test for the ECDSA part of the tinycrypt.
It generates keys, signs and verifies. Modified from tinycrypt
tests found in tinycrypt-repository.
This commit changes the internal identifiers
MBEDTLS_SSL_MINOR_VERSION_XXX
in DTLS-only builds to match the version encoding used by the
DTLS standard, encoding DTLS 1.0 as 255 and DTLS 1.2 as DTLS 1.0.
Accordingly, the version comparison functions introduced in the
previous commit must be re-implemented, as older version have
_larger_ identifiers now.
Further, since we identify DTLS 1.0 as MBEDTLS_SSL_MINOR_VERSION_2
and DTLS 1.2 as MBEDTLS_SSL_MINOR_VERSION_3, what remains is to
define MBEDTLS_SSL_MINOR_VERSION_{0|1}. While these don't have any
meaning meaning in DTLS, they still need to be set and obey the
ordering in the sense that the version comparison functions '<='
should attest that
MBEDTLS_SSL_MINOR_VERSION_i '<=' MBEDTLS_SSL_MINOR_VERSION_j
for i <= j. Since '<=' is actually >= and the wire format value
for DTLS 1.0 == MBEDTLS_SSL_MINOR_VERSION_2 is the 255, this
forces us to use values beyond 255, and hence to extend the
storage type for minor versions from uint8_t to uint16_t.
Moved some functions under defined to get rid of compiler warnings.
Functions moved under defines:
- mbedtls_x509_get_alg
- mbedtls_x509_get_alg_null
- mbedtls_x509_get_time
- mbedtls_x509_get_ext
- mbedtls_x509_sig_alg_gets
- mbedtls_x509_key_size_helper
Left one function (mbedtls_x509_write_names) as non static as it increased code size.
This doesn't make a difference after link time optimization because
tickets aren't used, but it yields more accurate code-size figures
from baremetal.sh.
No need to play tricks with macros and functions depending on whether
SHA256_SMALLER is enabled or not, with a static inline function all common
compilers (tested with arm-gcc, armcc5, arm-clang) will Do The Right Thing
depending on whether we told them to optimize for size or speed.
The TinyCrypt PK signature wrapper uses ASN.1 writing functions
for length and tag, accounting for the only dependency of the
baremetal build on ASN.1 writing.
Since all lengths to be encoded are below 128 Bytes and are hence
ASN.1 encoded as single Bytes, the dependency on ASN.1 writing can
be removed at low complexity by writing the length and tags directly.
Previously, this wasn't necessary because ecdh.h was included
through ssl.h, but now that this is no longer the case (because
ssl.h doesn't use ECDH), we have to include it explicitly.
Previously, ecp.h was included only if MBEDTLS_ECDH_C was set,
which broke the build in configurations using ECDSA, but not ECDH.
An example of such a config is configs/config-thread.h, which
uses ECJPAKE exclusively.
Moreover, the inclusion of ecdh.h isn't needed, because the header
only uses constants defined in the ECP module.
Extend scope of TC in ECDH-param extraction from CRT
Previously, TinyCrypt was only used for ECDHE-ECDSA/RSA ciphersuites.
This commit is a step towards using it for _all_ ciphersuites involving
ECDHE (specifically: ECDHE, ECDHE-PSK, static ECDH), extending the scope
of the use of TinyCrypt in the writing of the ClientKeyExchange message.
Extend scope of TC in ECDH-param extraction from CRT
Previously, TinyCrypt was only used for ECDHE-ECDSA/RSA ciphersuites.
This commit is a step towards using it for _all_ ciphersuites involving
ECDHE (specifically: ECDHE, ECDHE-PSK, static ECDH), extending the scope
of the use of TinyCrypt in the parsing of the ServerKeyExchange message.
Previously, TinyCrypt was only used for ECDHE-ECDSA/RSA ciphersuites.
This commit is a step towards using it for _all_ ciphersuites involving
ECDHE (specifically: ECDHE, ECDHE-PSK, static ECDH), extending the scope
of the use of TinyCrypt in the parsing of the ClientKeyExchange message.
Previously, TinyCrypt was only used for ECDHE-ECDSA/RSA ciphersuites.
This commit is a step towards using it for _all_ ciphersuites involving
ECDHE (specifically: ECDHE, ECDHE-PSK, static ECDH), extending the scope
of the use of TinyCrypt in the writing of the ServerKeyExchange message.
Extend scope of TC in ECDH-param extraction from CRT
Previously, TinyCrypt was only used for ECDHE-ECDSA/RSA ciphersuites.
This commit is a step towards using it for _all_ ciphersuites involving
ECDHE (specifically: ECDHE, ECDHE-PSK, static ECDH), extending the scope
of the use of TinyCrypt in the assembly of the PMS.
Previously, the TinyCrypt component in all.sh restricted the ssl-opt.sh
to the 'Default, DTLS' test, due to implicit dependencies on Secp384r1.
These dependencies are now explicit and ssl-opt.sh skips corresponding
tests accordingly, so we can introduce a full run of ssl-opt.sh into
the TinyCrypt test in all.sh.
This commit modifies ssl-opt.sh to autodetect the use of test certificates
server5.* server6.* test-ca2.* using Secp384r1, and skips the corresponding
tests if MBEDTLS_ECP_DP_SECP384R1_ENABLED isn't set.
Previously, the TinyCrypt all.sh test restricted the run of compat.sh
to DTLS 1.2 and listed a few explicit ciphersuites.
This commit widens the scope of the test by testing any ciphersuite
based on ECDHE-ECDSA, regardless of TLS/DTLS or the particular version.
Further, it doesn't exclude SHA-384 as done previously.
This commit uses the flexibility of being able to chose CRTs and keys
to be used by compat.sh through predefined environment variables to
force the use of Secp256r1 certificates and keys in the all.sh test
for TinyCrypt.
This commit introduces environment variables
- SRV_ECDSA_CRT
- SRV_ECDSA_KEY
- CLI_ECDSA_CRT
- CLI_ECDSA_KEY
- SRV_RSA_CRT
- SRV_RSA_KEY
- CLI_RSA_CRT
- CLI_RSA_KEY
- CA_FILE
to tests/compat.sh which hold the path of the CA, client and server
certificate and key files to use by the script.
This is a preparatory step towards switching to a different set of
certificates and keys in case the configuration doesn't match the
certificates in use so far (e.g.: the ECDSA certificates use Secp384r1,
so if that's disabled, ECDSA tests will fail).
There is no apparent direct dependency, and the indirect dependency
through the RSA and legacy ECP modules is already encoded in the
chain
MBEDTLS_X509_USE_C
-> MBEDTLS_PK_PARSE_C
-> MBEDTLS_PK_C
-> MBEDTLS_RSA_C || MBEDTLS_ECP_C
-> MBEDTLS_BIGNUM_C
which will be modified to
MBEDTLS_X509_USE_C
-> MBEDTLS_PK_PARSE_C
-> MBEDTLS_PK_C
-> MBEDTLS_RSA_C || MBEDTLS_ECP_C || MBEDTLS_USE_TINYCRYPT
in which case MBEDTLS_BIGNUM_C is not needed for MBEDTLS_X509_USE_C
if only MBEDTLS_USE_TINYCRYPT is set, but not MBEDTLS_RSA_C or
MBEDTLS_ECP_C.
asn1.h uses uint8_t which is defined in stdint.h.
This wasn't caught earlier by the luck that whenever asn1.h
was included, another header was included earlier that did in
turn include stdint.h.
Remark: Including ecp.h is actually redundant because it's
also included from ecdh.h. However, it's good practice to
explicitly include header files that are being used directly,
and ssl.h does use MBEDTLS_ECP_MAX_BYTES which is defined in ecp.h.
ssl.h contains a dummy union of fields each large enough to
hold the PMS for a particular ciphersuite. In particular, for
pure-ECDH ciphersuites, it contains a field large enough to
hold the ECDH shared secret in any of the enabled curves.
So far, this upper bound was unconditionally chosen to be
MBEDTLS_ECP_MAX_BYTES from the ECP module.
With the introduction of TinyCrypt as an alternative implementation
for ECDH, we need to
- guard the use of MBEDTLS_ECP_MAX_BYTES because MBEDTLS_ECP_C
is no longer implied by the surrounding MBEDTLS_KEY_EXCHANGE_XXX
guards
- add another field which contains the maximum length of shared
ECDH secrets for curves supported by TinyCrypt.
mbedtls/ecp.h defines constants
MBEDTLS_ECP_PF_UNCOMPRESSED
MBEDTLS_ECP_PF_COMPRESSED
MBEDTLS_ECP_TLS_NAMED_CURVE
which regard the encoding of elliptic curves and curve point formats in TLS.
As such, they should be defined in the SSL namespace. Asides, this will help
replacing the legacy ECC crypto by alternative ECC implementations.
Even though exhaustive testing of TinyCrypt is left for later,
without this test we don't have any evidence that PK writing
works for TinyCrypt-based PK context.
TinyCrypt only supports Secp256r1, so skip all tests in test_suite_x509parse
which use different curves, while splitting those which rely on Secp256r1
alone into two tests: one for legacy ECC, and one for TinyCrypt.
Studying and improving the TinyCrypt test coverage is left for a later commit.
The current pkwrite tests involving ECC all use curves different
from Secp256r1, so they don't apply to TinyCrypt.
Adding tests for TinyCrypt is left to a later commit.
- The underlying test vectors are for Secp192r1, while TinyCrypt uses Secp256r1.
- The test implementation is specific to the structure of legacy-ECC PK ctxs.
Addition of analogous tests for TinyCrypt-based ECC PK contexts are left
for a later commit.
PEM-encoded keys with PEM header
-----BEGIN EC PRIVATE KEY-----
...
-----END EC PRIVATE KEY-----
were previously not parsed in configurations using TinyCrypt
instead of legacy ECC crypto.
The PK type MBEDTLS_PK_ECDSA is never returned from
`mbedtls_pk_info_from_type()`. Instead, EC keys either
are identified as MBEDTLS_PK_ECKEY_DH (in case they
must only be used for ECDHE) or MBEDTLS_PK_ECKEY (in
case they can be used for any algorithm).
With TinyCrypt and legacy ECC mutually exclusive, we don't have
to use #if TINYCRYPT #else #if LEGACY #endif #endif anymore, but
can add the TC and legacy based ECC implementations independently.
- TinyCrypt uses `0` for errors.
- The first argument to uECC_verify() should be the public key,
but the previous code passed the beginning of the entire
private-public key structure.
The PK-type MBEDTLS_PK_ECDSA isn't really used by the library.
Especially, when parsing a generic EC key, a PK context of type
MBEDTLS_PK_ECKEY will be requested. Hence, to drop in TinyCrypt
for the legacy-ECC implementation, the PK type that TinyCrypt
implements must be MBEDTLS_PK_ECKEY.
TinyCrypt should be used as a replacement of legacy ECC. In particular,
there shouldn't be any use of identifiers from the legacy ECC module.
So far, there's the configuration option
MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
that's relevant if MBEDTLS_SSL_CONF_SINGLE_CURVE is set, and which in
this case must resolve to an identifier of type mbedtls_ecp_group_id
indicating which single curve to enable.
With the introduction of TinyCrypt, we must either change the type
of this option to mbedtls_uecc_group_id, or introduce a separate
compilation option.
In order to avoid type confusion, this commit follows tha latter
approach, introducing the configuration option
MBEDTLS_SSL_CONF_SINGLE_UECC_GRP_ID
that indicatesthe TinyCrypt group identifier of the single curve
to use (must be Secp256r1) if MBEDTLS_SSL_CONF_SINGLE_CURVE
and MBEDTLS_USE_TINYCRYPT are set.
So far, ssl_client2 and ssl_server2 were relying on MBEDTLS_CTR_DRBG_C
being set. This commit adapts them to use HMAC DRBG in case CTR DRBG
is disabled in the configuration.
Note that disabling CTR DRBG in favor of HMAC DRBG can be useful on
constrained systems because Mbed TLS' HMAC DRBG is slightly smaller,
and moreover needed anyway as part of deterministic ECDSA.
This commit splits each test in ssl-opt.sh related to context serialization
in three tests, exercising the use of CCM, GCM and ChaChaPoly separately.
The reason is that the choice of primitive affects the presence and size
of an explicit IV, and we should test that space for those IVs is correctly
restored during context deserialization; in fact, this was not the case
previously, as fixed in the last commit, and was not caught by the tests
because only ChaChaPoly was tested.
The SSL context maintains a set of 'out pointers' indicating the
address at which to write the header fields of the next outgoing
record. Some of these addresses have a static offset from the
beginning of the record header, while other offsets can vary
depending on the active record encryption mechanism: For example,
if an explicit IV is in use, there's an offset between the end
of the record header and the beginning of the encrypted data to
allow the explicit IV to be placed in between; also, if the DTLS
Connection ID (CID) feature is in use, the CID is part of the
record header, shifting all subsequent information (length, IV, data)
to the back.
When setting up an SSL context, the out pointers are initialized
according to the identity transform + no CID, and it is important
to keep them up to date whenever the record encryption mechanism
changes, which is done by the helper function ssl_update_out_pointers().
During context deserialization, updating the out pointers according
to the deserialized record transform went missing, leaving the out
pointers the initial state. When attemping to encrypt a record in
this state, this lead to failure if either a CID or an explicit IV
was in use. This wasn't caught in the tests by the bad luck that
they didn't use CID, _and_ used the default ciphersuite based on
ChaChaPoly, which doesn't have an explicit IV. Changing either of
this would have made the existing tests fail.
This commit fixes the bug by adding a call to ssl_update_out_pointers()
to ssl_context_load() implementing context deserialization.
Extending test coverage is left for a separate commit.
* mbedtls-2.16: (21 commits)
Exclude DTLS 1.2 only with older OpenSSL
Document the rationale for the armel build
Switch armel build to -Os
Add a build on ARMv5TE in ARM mode
Add changelog entry for ARM assembly fix
bn_mul.h: require at least ARMv6 to enable the ARM DSP code
Changelog entry for test certificates update
Change worktree_rev to HEAD for rev-parse
Add ChangeLog entry for entropy_nv_seed test case fix
entropy_nv_seed: cope with SHA-256
entropy_nv_seed: clean up properly
Add ChangeLog entry for undefined behavior fix in test_suite_nist_kw
Don't call memset after calloc
Adapt ChangeLog
ECP restart: Don't calculate address of sub ctx if ctx is NULL
Update certificates to expire in 2029
Update soon to be expired crl
Test that a shared library build produces a dynamically linked executable
Test that the shared library build with CMake works
Add a test of MBEDTLS_CONFIG_FILE
...
The NO_INLINE annotation of tls_prf_sha256() and tls_prf_sha384() from
the last commit surprisingly had an influence on ARMC5 compilation in
that tls_prf_generic() was no longer automatically inlined into
tls_prf_sha256() if only the latter was enabled (and is the point
where tls_prf_generic() is called). This commit forces inlining
of tls_prf_generic() in this case.
Usually, compilers are clever enough to pick the best inlining
strategy, but in this instance, it appears that compiling on ARMC6,
the compilers inlines xxx_prf_yyy() and xxx_calc_finished_yyy()
even though it really shouldn't. Forbid inlining through the use
of __attribute__((noinline)).
Somehow, at least ARMC5 isn't able to recognize this automatically.
Since some of the arguments to ssl_populate_transform() are compile-
time constants in reduced configurations, inlining leads to slightly
shorter code.
This saves a few bytes in configurations where only one hash
is enabled, and configurations allowing multiple hashes probably
don't care about code-size anyway.
This function is called on client-only once the ciphersuite has
been chosen and it it is known which digest the client will need
for the handshake transcript throughout the handshake, and causes
all other unneeded handshake transcripts to be discontinued.
(On the server, we cannot call this function because we don't know
which hash the client will those in its CertificateVerify message).
However, the benefit of this call is marginal, since transcript hash
computation is negligible compared to asymmetric crypto, and moreover
the handshake transcript contexts for the unused digests are still
stored in the SSL handshake parameter structure and not freed until
the end of the handshake.
Finally, if we're running on a _really_ constrained client, there
will be only one hash function enabled anyway, and in this case
the checksum optimization has no effect.
This commit therefore removes checksum optimization altogether,
saving some code on constrained systems.
- a comment regarding the implementation of hmac_drbg_reseed_core()
was misplaced.
- add more references to the standard, and add details on how the
comments in the code refer to various parts of the standard.
Now function mbedtls_ssl_set_hostname is compile-time configurable
in config.h with define MBEDTLS_X509_REMOVE_HOSTNAME_VERIFICATION.
This affects to many x509 API's. See config.h for details.
ssl_client2 and ssl_server2 either allow loading specific CRTs
and CAs from files, or to leave them unspecified, in which case
they're automatically picked from the test certificates.
The test certificates should be chosen in a way that when
not specifying any CRT or CA parameters, the automatically
chosen ones match - but if one of them is specified but not
the other, one should not expect tests to succeed.
With the recent switch to Secp256r1-based test certificates,
the default test certificates have changed, which breaks some
ssl-opt.sh tests which specify the server CRT explicitly but
not the client trusted CAs.
This commit fixes this by specifying the client's trusted CA
explicitly in accordance with the explicitly specified server CRT.
According to SP800-90A, the DRBG seeding process should use a nonce
of length `security_strength / 2` bits as part of the DRBG seed. It
further notes that this nonce may be drawn from the same source of
entropy that is used for the first `security_strength` bits of the
DRBG seed. The present HMAC DRBG implementation does that, requesting
`security_strength * 3 / 2` bits of entropy from the configured entropy
source in total to form the initial part of the DRBG seed.
However, some entropy sources may have thresholds in terms of how much
entropy they can provide in a single call to their entropy gathering
function which may be exceeded by the present HMAC DRBG implementation
even if the threshold is not smaller than `security_strength` bits.
Specifically, this is the case for our own entropy module implementation
which only allows requesting at most 32 Bytes of entropy at a time
in configurations disabling SHA-512, and this leads to runtime failure
of HMAC DRBG when used with Mbed TLS' own entropy callbacks in such
configurations.
This commit fixes this by splitting the seed entropy acquisition into
two calls, one requesting `security_strength` bits first, and another
one requesting `security_strength / 2` bits for the nonce.
Previously, configs/baremetal_test.h added MBEDTLS_ECP_DP_SECP384R1_ENABLED
because we didn't have sufficient test certificates using Secp256r1. Now that
these test certificates have been added, we can successfully run
ssl_client2 and ssl_server2 with just Secp256r1 enabled.
This commit adds the script scripts/generate_certs.sh which
parses library/certs.c and inserts certificate and key files
for any block of the form
/* BEGIN FILE [string|binary] [variable|macro] NAME FILE */
...
/* END FILE */
Here, the first argument string / binary indicates whether the
file should be inserted as a string or as a binary array. The
second argument indicates whether the resulting object should
be registered as a C variable or a macro.
This script allows to easily update certs.c in case any of the
test certificates from tests/data_files change, or new test
certificates / keys need to be added.
One test for running with MBEDTLS_ECDH_C on and one
for running MBEDTLS_ECDH_C off. Run ssl-opt.sh with Default, DTLS
and compatibility tests with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA.
tinyCrypt is still tested in the baremetal tests since it
is enabled in baremetal.h. Tests for minimal modifictions
of the default / full config enabling tinyCrypt will be
added elsewhere.
The use of tinyCrypt is restricted Secp256r1-only, and a check in
ssl_ciphersuite_is_match() ensures that an EC ciphersuite is chosen
only if the client advertised support for Secp256r1, too.
In a way inconsistent with the rest of the library restricting the
use of tinyCrypt to pure-ECDHE, the previous ServerKeyExchange writing
routine would use tinyCrypt also for ECDHE-PSK-based ciphersuites.
This commit fixes this.
Previously, MBEDTLS_KEY_EXCHANGE_ECDH[E]_XXX_ENABLED would imply
that MBEDTLS_ECDH_C is set, but with the introduction of tinyCrypt
as an alternative ECDH implementation, this is no longer the case.
tinyCrypt uses a global RNG without context parameter while Mbed TLS in its
default configuration uses RNG+CTX bound to the SSL configuration.
This commit restricts the use of tinyCrypt to configurations that use a
global RNG function with NULL context by setting MBEDTLS_SSL_CONF_RNG in
the configuration. This allows to define a wrapper RNG to be used by
tinyCrypt which maps to this global hardcoded RNG.
Eventually, all HS parsing/writing functions should take an arbitrary buffer +
length pair as their argument, and return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if
the provided buffer is too short. So far, we've only made a first step by
allowing to pass an arbitrary buffer, but don't yet add bounds checks
throughout. While deliberate for now, this must be clearly documented.
This makes grepping the functions more difficult, and also leads to compilation failures
when trying to build the library from a single source file (which might be useful for
code-size reasons).
Previously, ssl_ecrs_ske_start_processing was used to indicate that
the ServerKeyExchange has been fetched from the record layer, but
that parsing its ECDHE parameter component has been preempted by the
restartable ECP feature. On re-entry of ssl_parse_server_key_exchange()
in this state, the code would directly jump into the parsing routine.
However, the only non-reentrant code that's jumped over this way is
the record fetching routine mbedtls_ssl_parse_record(), which is now
made re-entrant by setting `ssl->keep_current_message = 1` in case of
pre-emption due to restartable ECC.
The ssl_ecrs_ske_start_processing state is therefore redundant and
can be removed, which is what this commit does.
IAR doesn't like `((void) var);` as a means to indicate an unused
variable if that variable hasn't been initialized before. Make it
happy by initializing the variable before.
ssl_server_key_exchange_parse() is compiled even if there's no ciphersuite
enabled which uses it (for example, that's the case in RSA-only builds).
The rationale for that is to avoid cluttering the code with numerous
compile-time guards. A consequence, however, is the top of
ssl_server_key_exchange_parse() contains declarations for variables
which are never put to use, and rightfully leading to compiler warnings.
This commit silences these warnings by putting `((void) VAR);` statements
in the branch which detects if we ever happen to call the function in an
unexpected ciphersuite.
In the PSK and RSA-PSK ciphersuites, the ServerKeyExchange message
MAY be skipped. This commit moves the code-path peeking at the
incoming message to decide whether it's probably a ServerKeyExchange
to the new coordination function ssl_server_key_exchange_coordinate().
This commit moves the code checking whether a SrvKeyExchange message
is expected or not to the new function ssl_srv_key_exchange_coordinate().
Note that the potential static DH extraction is done prior to the
coordination step.
This code moves the code-path that extracts static DH parameters
from the server's CRT (if applicable) to the new function
ssl_server_key_exchange_prepare().
This commit adds declarations and dummy implementations for
the restructured incoming server key exchange handling that
will replace the previous ssl_parse_server_key_exchange().
The entry point for the SrvKeyExchange handling that is called
from the handshake state machine is
`ssl_process_server_key_exchange()`,
splitting the processing into the following steps:
- Preparation: For a static DH key exchange, extract
DH parameters from the server's CRT.
- Coordination: Check if a SrvKeyExchange message is expected
(e.g., it isn't for a RSA-based key exchange)
- Reading: Fetch and check content and handshake type
of incoming message.
- Parsing: Parse and store the ServerKeyExchange message.
- Postprocessing: Update handstate state machine.
The subsequent commits will scatter the code from the previous
monolithic function ssl_parse_server_key_exchange() among those
dedicated functions, commenting out each part of
ssl_parse_server_key_exchange() that has already been dealt with.
This gradual progression is meant to ease reviewing. Once all
code has been moved and all changes explained,
ssl_parse_server_key_exchange() will be removed.
The postprocessing code for the server-side incoming client key
exchange and the client-side outgoing client key exchange both
contain the same code-paths for building the premaster secret
depending on the chosen ciphersuite (e.g., for ECDHE-PSK,
concatenating the ECDHE secret with the chosen PSK).
This commit moves this common code to ssl_tls.c, allowing
client- and server-side to share it.
The code from the previous function ssl_parse_client_key_exchange()
has been entirely moved to one of the newly introduced subroutines
and is no longer needed. This commit removes it.
After parsing and performing key generation operations,
the server-side incoming ClientKeyExchange handling includes
code-paths to assembly the PreMasterSecret (PMS) from the
available keying material, the exact assembly procedure
depending on which ciphersuite is in use. E.g., in an
(EC)DHE-PSK ciphersuite, the (EC)DHE secret would be concatenated
with the PSK to form the PMS.
This assembly of the PMS logically comes done after the ClientKeyExchange
has been parsed and the respective keying material has been generated,
and this commit moves it to the new postprocessing function
ssl_client_key_exchange_postprocess().
This commit moves the generation of the master secret and session keys
from the premaster secret (done in mbedtlsssl_derive_keys()) from the
previous ClientKeyExchange parsing function ssl_parse_client_key_exchange()
to the new postprocessing function ssl_client_key_exchange_postprocess().
This commit adds declarations and dummy implementations for
the restructured incoming client key exchange handling that
will replace the previous ssl_parse_client_key_exchange().
The entry point for the CliKeyExchange handling that is called
from the handshake state machine is
`ssl_process_client_key_exchange()`,
splitting the processing into the following steps:
- Fetching: Read next message from the messaging layer
and check that it has the correct type.
The ClientKeyExchange message is never
omitted, so there is no ambiguity in what
to expect, and hence no dedicated preparation
step as for other handshake states.
- Parsing: Parse the ClientKeyExchange message and
use the information in it to derive keying
material such as the shared (EC)DHE secret.
- Postprocessing:
Compute the session keys from the available
keying material. This splits in two steps:
(1) Build the PreMasterSecret (PMS) from the
available keying material, e.g. concatenate
the (EC)DHE secret with a PSK, if used.
(2) Extract the MasterSecret and Session Keys
from the PreMasterSecret.
The subsequent commits will scatter the code from the previous
monolithic function ssl_parse_client_key_exchange() among those
dedicated functions, commenting out each part of
ssl_parse_client_key_exchange() that has already been dealt with.
This gradual progression is meant to ease reviewing. Once all
code has been moved and all changes explained,
ssl_parse_client_key_exchange() will be removed.
The code from the previous function ssl_write_client_key_exchange()
has been entirely moved to one of the newly introduced subroutines
and is no longer needed. This commit removes it.
This commit moves the code responsible for
(a) generating the client's private and public (EC)DHE keys
(b) writing it to the message buffer
to the new writing function ssl_client_key_exchange_write().
As mentioned in the previous commit message, (a) and (b) are
currently inseparable at the (EC)DHE API level, which is why
(a) can't be moved to the preparation step.
For RSA or RSA-PSK exchanges, the PMS contains 46 random bytes
picked by the client. These bytes are generated prior to the
writing of the ClientKeyExchange message.
This commit splits the previous function ssl_write_encrypted_pms() into
PPMS-GEN: ssl_rsa_generate_partial_pms()
PPMS-ENC: ssl_rsa_encrypt_partial_pms().
The prefix 'partial' is meant to emphasize that the generation of the PMS
is not always entirely done by these functions: For RSA-PSK e.g., the
PSK still needs to be added.
The two calls of ssl_write_encrypted_pms() in
ssl_write_client_key_exchange() will split in calls of the functions
PPMS-GEN and PPMS-ENC each, with PPMS-GEN being moved to the new
preparation function ssl_client_key_exchange_prepare() in this commit,
and PPMS-ENC being moved to ssl_client_key_exchange_write() in the
next commit.
After and performing key generation operations,
the client-side outgoing ClientKeyExchange handling includes
code-paths to assembly the PreMasterSecret (PMS) from the
available keying material, the exact assembly procedure
depending on which ciphersuite is in use. E.g., in an
(EC)DHE-PSK ciphersuite, the (EC)DHE secret would be concatenated
with the PSK to form the PMS.
This assembly of the PMS logically can be done after the ClientKeyExchange
has been written and the respective keying material has been generated,
and this commit moves it to the new postprocessing function
ssl_client_key_exchange_postprocess().
Ideally, the PMS assembly could be done prior to writing the
ClientKeyExchange message, but the (EC)DHE API does currently
not allow splitting secret-generation and secret-export; as
long as that's the case, we to generation and exporting in the
message writing function, forcing PMS assembly to be done in
the postprocessing.
This commit adds declarations and dummy implementations for
the restructured outgoing client key exchange handling that
will replace the previous ssl_write_client_key_exchange().
The entry point for the CliKeyExchange handling that is called
from the handshake state machine is
`ssl_process_client_key_exchange()`,
splitting the processing into the following steps:
- Preparation
Compute the keying material to be sent.
* For (EC)DH: Pick parameters and compute PMS.
* For ECJPAKE: Run round 2
* For RSA: Encrypt PMS
- Writing: Prepare the writing of a new messae.
- Postprocessing: Update handstate state machine.
The subsequent commits will scatter the code from the previous
monolithic function ssl_write_client_key_exchange() among those
dedicated functions, commenting out each part of
ssl_write_client_key_exchange() that has already been dealt with.
This gradual progression is meant to ease reviewing. Once all
code has been moved and all changes explained,
ssl_write_client_key_exchange() will be removed.
* mbedtls-2.16:
Fix parsing issue when int parameter is in base 16
Refactor receive_uint32()
Refactor get_byte function
Make the script portable to both pythons
Update the test encoding to support python3
update the test script
tests: Limit each log to 10 GiB
It happens regularly in test runs that the server example application
shuts down a connection, goes into waiting mode for a new connection,
and then receives the encrypted ClosureAlert from the client. The only
reason why this does currently not trigger the 'record from another epoch'
message is that we handle ClientHello parsing outside of the main record
stack because we want to be able to detect SSLv2 ClientHellos. However,
this is likely to go away, and once it happens, we'll see the log message.
Further, when record checking is used, every record, including the mentioned
closure alert, is passed to the record checking API before being passed to
the rest of the stack, which leads to the log message being printed.
In summary, grepping for 'record from another epoch' is a fragile way
of checking whether a reordered message has arrived. A more reliable
way is to grep for 'Buffer record from epoch' which is printed when
a record from a future epoch is actually buffered, and 'ssl_buffer_message'
which is the function buffering a future handshake message.
This commit implements the record checking API
mbedtls_ssl_check_record()
on top of the restructured incoming record stack.
Specifically, it makes use of the fact that the core processing routines
ssl_parse_record_header()
mbedtls_ssl_decrypt_buf()
now operate on instances of the SSL record structure mbedtls_record
instead of the previous mbedtls_ssl_context::in_xxx fields.
After the rewrite of incoming record processing to use the internal
SSL record structure mbedtls_record (which contains the data_offset
field to indicate where the IV resides), this field is no longer
necessary.
Note: This is an API break.
The function mbedtls_ssl_in_hdr_len() is supposed to return the length
of the record header of the current incoming record. With the advent
of the DTLS Connection ID, this length is only known at runtime and
hence so far needed to be derived from the internal in_iv pointer
pointing to the beginning of the payload of the current incooing
record.
By now, however, those uses of mbedtls_ssl_in_hdr_len() where the
presence of a CID would need to be detected have been removed
(specifically, ssl_parse_record_header() doesn't use it anymore
when checking that the current datagram is large enough to hold
the record header, including the CID), and it's sufficient to
statically return the default record header sizes of 5 / 13 Bytes
for TLS / DTLS.
ssl_get_next_record() updates the legacy in_xxx fields in two places,
once before record decryption and once after. Now that record decryption
doesn't use or affect the in_xxx fields anymore, setting up the these
legacy fields can entirely be moved to the end of ssl_get_next_record(),
which is what this comit does.
This commit solely moves existing code, but doesn't yet simplify the
now partially redundant settings of the in_xxx fields. This will be
done in a separate commit.
Multiple record attributes such as content type and payload length
may change during record decryption, and the legacy in_xxx fields
in the SSL context therefore need to be updated after the record
decryption routine ssl_decrypt_buf() has been called.
After the previous commit has made ssl_prepare_record_content()
independent of the in_xxx fields, setting them can be moved
outside of ssl_prepare_record_content(), which is what this
commit does.
Previously, ssl_update_in_pointers() ensured that the in_xxx pointers
in the SSL context are set to their default state so that the record
header parsing function ssl_parse_record_header() could make use of them.
By now, the latter is independent of these pointers, so they don't need
to be setup before calling ssl_parse_record_header() anymore.
However, other parts of the messaging stack might still depend on it
(to be studied), and hence this commit does not yet reomve
ssl_update_in_pointers() entirely.
The stack maintains pointers mbedtls_ssl_context::in_xxx pointing to
various parts of the [D]TLS record header. Originally, these fields
were determined and set in ssl_parse_record_header(). By now,
ssl_parse_record_header() has been modularized to setup an instance
of the internal SSL record structure mbedtls_record, and to derive
the old in_xxx fields from that.
This commit takes a further step towards removing the in_xxx fields
by deriving them from the established record structure _outside_ of
ssl_parse_record_header() after the latter has succeeded.
One exception is the handling of possible client reconnects,
which happens in the case then ssl_parse_record_header() returns
MBEDTLS_ERR_SSL_UNEXPECTED_RECORD; since ssl_check_client_reconnect()
so far uses the in_xxx fields, they need to be derived from the
record structure beforehand.
This commit makes a first step towards modularizing the incoming record
processing by having it operate on instances of the structure mbedtls_record
representing SSL records.
So far, only record encryption/decryption operate in terms of record
instances, but the rest of the parsing doesn't. In particular,
ssl_parse_record_header() operates directly on the fixed input buffer,
setting the various ssl->in_xxx pointers and fields, and only directly
before/after calling ssl_decrypt_buf() these fields a converted to/from
mbedtls_record instances.
This commit does not yet remove the ssl->in_xxx fields, but makes a step
towards extending the lifetime of mbedtls_record structure representing
incoming records, by modifying ssl_parse_record_header() to setup an
instance of mbedtls_record, and setting the ssl->in_xxx fields from that
instance. The instance so-constructed isn't used further so far, and in
particular it is not yet consolidated with the instance set up for use
in ssl_decrypt_record(). That's for a later commit.
Previously, ssl_parse_record_header() did not check whether the current
datagram is large enough to hold a record of the advertised size. This
could lead to records being silently skipped over or backed up on the
basis of an invalid record length. Concretely, the following would happen:
1) In the case of a record from an old epoch, the record would be
'skipped over' by setting next_record_offset according to the advertised
but non-validated length, and only in the subsequent mbedtls_ssl_fetch_input()
it would be noticed in an assertion failure if the record length is too
large for the current incoming datagram.
While not critical, this is fragile, and also contrary to the intend
that MBEDTLS_ERR_SSL_INTERNAL_ERROR should never be trigger-able by
external input.
2) In the case of a future record being buffered, it might be that we
backup a record before we have validated its length, hence copying
parts of the input buffer that don't belong to the current record.
This is a bug, and it's by luck that it doesn't seem to have critical
consequences.
This commit fixes this by modifying ssl_parse_record_header() to check that
the current incoming datagram is large enough to hold a record of the
advertised length, returning MBEDTLS_ERR_SSL_INVALID_RECORD otherwise.
We don't send alerts on other instances of ill-formed records,
so why should we do it here? If we want to keep it, the alerts
should rather be sent ssl_get_next_record().
As explained in the previous commit, if mbedtls_ssl_fetch_input()
is called multiple times, all but the first call are equivalent to
bounds checks in the incoming datagram.
In DTLS, if mbedtls_ssl_fetch_input() is called multiple times without
resetting the input buffer in between, the non-initial calls are functionally
equivalent to mere bounds checks ensuring that the incoming datagram is
large enough to hold the requested data. In the interest of code-size
and modularity (removing a call to a non-const function which is logically
const in this instance), this commit replaces such a call to
mbedtls_ssl_fetch_input() by an explicit bounds check in
ssl_parse_record_header().
Previously, `ssl_handle_possible_reconnect()` was part of
`ssl_parse_record_header()`, which was required to return a non-zero error
code to indicate a record which should not be further processed because it
was invalid, unexpected, duplicate, .... In this case, some error codes
would lead to some actions to be taken, e.g. `MBEDTLS_ERR_SSL_EARLY_MESSAGE`
to potential buffering of the record, but eventually, the record would be
dropped regardless of the precise value of the error code. The error code
`MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED` returned from
`ssl_handle_possible_reconnect()` did not receive any special treatment and
lead to silent dopping of the record - in particular, it was never returned
to the user.
In the new logic this commit introduces, `ssl_handle_possible_reconnect()` is
part of `ssl_check_client_reconnect()` which is triggered _after_
`ssl_parse_record_header()` found an unexpected record, which is already in
the code-path eventually dropping the record; we want to leave this code-path
only if a valid cookie has been found and we want to reset, but do nothing
otherwise. That's why `ssl_handle_possible_reconnect()` now returns `0` unless
a valid cookie has been found or a fatal error occurred.
Availability of sufficient incoming data should be checked when
it is needed, which is in mbedtls_ssl_fetch_input(), and this
function has the necessary bounds checks in place.
mbedtls_ssl_decrypt_buf() asserts that the passed transform is not NULL,
but the function is only invoked in a single place, and this invocation
is clearly visible to be within a branch ensuring that the incoming
transform isn't NULL. Remove the assertion for the benefit of code-size.
The previous code performed architectural maximum record length checks
both before and after record decryption. Since MBEDTLS_SSL_IN_CONTENT_LEN
bounds the maximum length of the record plaintext, it suffices to check
only once after (potential) decryption.
This must not be confused with the internal check that the record
length is small enough to make the record fit into the internal input
buffer; this is done in mbedtls_ssl_fetch_input().
The check is in terms of the internal input buffer length and is
hence likely to be originally intended to protect against overflow
of the input buffer when fetching data from the underlying
transport in mbedtls_ssl_fetch_input(). For locality of reasoning,
it's better to perform such a check close to where it's needed,
and in fact, mbedtls_ssl_fetch_input() _does_ contain an equivalent
bounds check, too, rendering the bounds check in question redundant.
When looking for a parent, all candidates were considered time-invalid due to
the #ifdef incorrectly including the `parent_valid = 1` line.
When MBEDTLS_HAVE_TIME_DATE is unset the time-validity of certificates is
never checked and always treated as valid. This is usually achieved by proper
usage of mbedtls_x509_time_is_past() and mbedtls_x509_time_is_future() (and
their definition when we don't HAVE_TIME_DATE).
Here the calls to these functions needs to be guarded by
MBEDTLS_X509_CRT_REMOVE_TIME as they access struct members whose presence is
controlled by this option. But the "valid" branch should still always be taken.
(Note: MBEDTLS_X509_CRT_REMOVE_TIME being set forces MBEDTLS_HAVE_TIME_DATE to
be unset, as enforce by check_config.h.)
This bug was found by `all.sh test_baremetal` - no need for a new test.
This was found as a warning when running scripts/baremetal.sh --ram
--build-only manually, but it should have been found in a more automated way.
Adding -Werror so that future such issues will be caught by all.sh
(component_test_baremetal already invokes baremetal.sh --ram --build-only).
Asserting `*p == end` right after setting `end = *p + len` will always fail
unless `len == 0`, which is never the case with properly-formed certificates.
The function x509_skip_dates() is modelled after x509_get_dates() which between
setting `end` and comparing it to `*p` calls mbedtls_x509_get_time() which
advances `*p` to the expected value, which is why this test works in
get_dates().
Since `skip_dates()` has `skip`, not `validate` in its name, and the entire
point of `MBEDTLS_X509_CRT_REMOVE_TIME` is to save code, we don't want to
call the relatively large functions needed to properly parse (and validate)
dates before throwing the parsed dates away, we can just fast-forward to the
end of the sequence.
This makes updating `end` and comparing it to `*p` after the fast-forward
redundant, as the comparison will always be true (unlike the case where we
actually parse the contents of the sequence).
This bug was found by `all.sh test_baremetal` - no need for a new test.
This option builds the library, tests and example programs
in a minimally modified baremetal.h configuration (modifications
from baremetal_test.h) but doesn't execute any tests.
Breaking into a series of statements makes things easier when stepping through
the code in a debugger.
Previous comments we stating the opposite or what the code tested for (what we
want vs what we're erroring out on) which was confusing.
Also expand a bit on the reasons for these restrictions.
ssl_get_next_record() may pend fatal alerts in response to receiving
invalid records. Previously, however, those were never actually sent
because there was no code-path checking for pending alerts.
This commit adds a call to ssl_send_pending_fatal_alert() after
the invocation of ssl_get_next_record() to fix this.
This function is often called when there's already an error code to handle,
and one of the reasons to introduce the pending of alerts was to _not_ have
another potential error code to take care of. Reflect this by making `void`
the return type of `mbedtls_ssl_pend_fatal_alert()`.
Modelled after the config-checking header from session s11n.
The list of relevant config flags was established by manually checking the
fields serialized in the format, and which config.h flags they depend on.
This probably deserves double-checking by reviewers.
Since the type of cid_len is unsigned but shorter than int, it gets
"promoted" to int (which is also the type of the result), unless we make the
other operand an unsigned int which then forces the expression to unsigned int
as well.
The code wants timer callbacks to be set (checked in fetch_input()), and can't
easily check whether we're using nbio, so it seems easier to require the
callbacks to be always set rather than only with nbio as was previously done.
context_buf was never free()d. Moreover, since we want to free it on error
paths as well, and even properly zeroize it in order to demonstrate good
memory hygiene, we need to make it and its length main()-scoped.
Previously it was missing reset in case 1, and in case 2 the code was never
executed as the option value was reset to 0.
Tighten checking of return values of save(NULL, 0) now that it works.
Also, improve the printed output as well as the comments.
I checked manually that everything now works and fail in the expected way:
save, reset-or-reinit and load all succeed, but the subsequent read or write
fails.
The number of meaning of the flags will be determined later, when handling the
relevant struct members. For now three bytes are reserved as an example, but
this number may change later.
This mainly follows the design document (saving all fields marked "saved" in
the main structure and the transform sub-structure) with two exceptions:
- things related to renegotiation are excluded here (there weren't quite in
the design document as the possibility of allowing renegotiation was still
on the table, which is no longer is) - also, ssl.secure_renegotiation (which
is not guarded by MBEDTLS_SSL_RENEGOTIATION because it's used in initial
handshakes even with renegotiation disabled) is still excluded, as we don't
need it after the handshake.
- things related to Connection ID are added, as they weren't present at the
time the design document was written.
The exact format of the header (value of the bitflag indicating compile-time
options, whether and how to merge it with the serialized session header) will
be determined later.
Enforce restrictions indicated in the documentation.
This allows to make some simplifying assumptions (no need to worry about
saving IVs for CBC in TLS < 1.1, nor about saving handshake data) and
guarantees that all values marked as "forced" in the design document have the
intended values and can be skipped when serialising.
Some of the "forced" values are not checked because their value is a
consequence of other checks (for example, session_negotiated == NULL outside
handshakes). We do however check that session and transform are not NULL (even
if that's also a consequence of the initial handshake being over) as we're
going to dereference them and static analyzers may appreciate the info.
At that point, the timer might not yet be configured.
The timer is reset at the following occasions:
- when it is initially configured through
mbedtls_ssl_set_timer_cb() or
mbedtls_ssl_set_timer_cb_cx()
- when a session is reset in mbedtls_ssl_session_reset()
- when a handshake finishes via mbedtls_ssl_handshake_wrap()
All modules using restartable ECC operations support passing `NULL`
as the restart context as a means to not use the feature.
The restart contexts for ECDSA and ECP are nested, and when calling
restartable ECP operations from restartable ECDSA operations, the
address of the ECP restart context to use is calculated by adding
the to the address of the ECDSA restart context the offset the of
the ECP restart context.
If the ECP restart context happens to not reside at offset `0`, this
leads to a non-`NULL` pointer being passed to restartable ECP
operations from restartable ECDSA-operations; those ECP operations
will hence assume that the pointer points to a valid ECP restart
address and likely run into a segmentation fault when trying to
dereference the non-NULL but close-to-NULL address.
The problem doesn't arise currently because luckily the ECP restart
context has offset 0 within the ECDSA restart context, but we should
not rely on it.
This commit fixes the passage from restartable ECDSA to restartable ECP
operations by propagating NULL as the restart context pointer.
Apart from being fragile, the previous version could also lead to
NULL pointer dereference failures in ASanDbg builds which dereferenced
the ECDSA restart context even though it's not needed to calculate the
address of the offset'ed ECP restart context.
This commit introduces the option MBEDTLS_SSL_CONF_SINGLE_HASH
which can be used to register a single supported signature hash
algorithm at compile time. It replaces the runtime configuration
API mbedtls_ssl_conf_sig_hashes() which allows to register a _list_
of supported signature hash algorithms.
In contrast to other options used to hardcode configuration options,
MBEDTLS_SSL_CONF_SINGLE_HASH isn't a numeric option, but instead it's
only relevant if it's defined or not. To actually set the single
supported hash algorithm that should be supported, numeric options
MBEDTLS_SSL_CONF_SINGLE_HASH_TLS_ID
MBEDTLS_SSL_CONF_SINGLE_HASH_MD_ID
must both be defined and provide the TLS ID and the Mbed TLS internal
ID and the chosen hash algorithm, respectively.
mbedtls_ssl_set_calc_verify_md() serves two purposes:
(a) It checks whether a hash algorithm is suitable to be used
in the CertificateVerify message.
(b) It updates the function callback pointing to the function that
computes handshake transcript for the CertificateVerify message
w.r.t. the chosen hash function.
Step (b) is only necessary when receiving the CertificateVerify
message, while writing the CertificateRequest only involves (a).
This commit modifies the writing code for the CertificateRequest
message to inline the check (a) and thereby avoiding the call to
mbedtls_ssl_calc_verify_md().
mbedtls_ssL_set_calc_verify_md() is used to select valid hashes when
writing the server's CertificateRequest message, as well as to verify
and act on the client's choice when reading its CertificateVerify
message.
If enabled at compile-time and configured via mbedtls_ssl_conf_sig_hashes()
the current code also offers SHA-1 in TLS 1.2. However, the SHA-1-based
handshake transcript in TLS 1.2 is different from the SHA-1 handshake
transcript used in TLS < 1.2, and we only maintain the latter
(through ssl_update_checksum_md5sha1()), but not the former.
Concretely, this will lead to CertificateVerify verification failure
if the client picks SHA-1 for the CertificateVerify message in a TLS 1.2
handshake.
This commit removes SHA-1 from the list of supported hashes in
the CertificateRequest message, and adapts two tests in ssl-opt.sh
which expect SHA-1 to be listed in the CertificateRequest message.
mbedtls_ssl_set_calc_verify_md() is only called from places
where it has been checked that TLS 1.2 is being used. The
corresponding compile-time and runtime guards checking the
version in mbedtls_ssl_set_calc_verify_md() are therefore
redundant and can be removed.
The previous code writes the content (the EC curve list) of the extension
before writing the extension length field at the beginning, which is common
in the library in places where we don't know the length upfront. Here,
however, we do traverse the EC curve list upfront to infer its length
and do the bounds check, so we can reorder the code to write the extension
linearly and hence improve readability.
This commit introduces the option MBEDTLS_SSL_CONF_SINGLE_EC
which can be used to register a single supported elliptic curve
at compile time. It replaces the runtime configuration API
mbedtls_ssl_conf_curves() which allows to register a _list_
of supported elliptic curves.
In contrast to other options used to hardcode configuration options,
MBEDTLS_SSL_CONF_SINGLE_EC isn't a numeric option, but instead it's
only relevant if it's defined or not. To actually set the single
elliptic curve that should be supported, numeric options
MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID
MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
must both be defined and provide the TLS ID and the Mbed TLS internal
ID and the chosen curve, respectively.
For both client/server the EC curve list is assumed not to be NULL:
- On the client-side, it's assumed when writing the
supported elliptic curve extension:
c54ee936d7/library/ssl_cli.c (L316)
- On the server, it is assumed when searching for a
suitable curve for the ECDHE exchange:
c54ee936d7/library/ssl_srv.c (L3200)
It is therefore not necessary to check this in mbedtls_ssl_check_curve().
ssl_write_supported_elliptic_curves_ext() is guarded by
```
#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
```
each of which implies (by check_config.h) that MBEDTLS_ECP_C
is enabled.
The fields
- mbedtls_ssl_handshake_params::max_major_ver,
- mbedtls_ssl_handshake_params::max_minor_ver
are used only for server-side RSA-based key exchanges
can be removed otherwise.
Reasons:
- If the transport type is fixed at compile-time,
mbedtls_ssl_read_version() and mbedtls_ssl_write_version()
are called with a compile-time determined `transport`
parameter, so the transport-type branch in their body
can be eliminated at compile-time.
- mbedtls_ssl_read_version() is called with addresses of
local variables, which so far need to be put on the stack
to be addressable. Inlining the call allows to read directly
into the registers holding these local variables.
This saves 60 bytes w.r.t. the measurement performed by
> ./scripts/baremetal.sh --rom --gcc
If the minor/major version is enforced at compile-time, the `major_ver`
and `minor_ver` fields in `mbedtls_ssl_context` are redundant and can
be removed.
This commit introduces the numeric compile-time constants
- MBEDTLS_SSL_CONF_MIN_MINOR_VER
- MBEDTLS_SSL_CONF_MAX_MINOR_VER
- MBEDTLS_SSL_CONF_MIN_MAJOR_VER
- MBEDTLS_SSL_CONF_MAX_MAJOR_VER
which, when defined, overwrite the runtime configurable fields
mbedtls_ssl_config::min_major_ver etc. in the SSL configuration.
As for the preceding case of the ExtendedMasterSecret configuration,
it also introduces and puts to use getter functions for these variables
which evaluate to either a field access or the macro value, maintaining
readability of the code.
The runtime configuration API mbedtls_ssl_conf_{min|max}_version()
is kept for now but has no effect if MBEDTLS_SSL_CONF_XXX are set.
This is likely to be changed in a later commit but deliberately omitted
for now, in order to be able to study code-size benefits earlier in the
process.
This commit restructures ssl_ciphersuites.h and ssl_ciphersuites.c to
define all ciphersuite helper functions static inline in ssl_ciphersuites.h
if MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE is set, and to otherwise put their
definitions in ssl_ciphersuites.c.
If MBEDTLS_SSL_SINGLE_CIPHERSUITE is enabled, the type
mbedtls_ssl_ciphersuite_handle_t
is logically a boolean (concretely realized as `unsigned char`),
containing the invalid handle and the unique valid handle, which
represents the single enabled ciphersuite.
The SSL session structure mbedtls_ssl_session contains an instance
of mbedtls_ssl_ciphersuite_handle_t which is guaranteed to be valid,
and which is hence redundant in any two-valued implementation of
mbedtls_ssl_ciphersuite_handle_t.
This commit replaces read-uses of
mbedtls_ssl_session::ciphersuite_info
by a getter functions which, and defines this getter function
either by just reading the field from the session structure
(in case MBEDTLS_SSL_SINGLE_CIPHERSUITE is disabled), or by
returning the single valid ciphersuite handle (in case
MBEDTLS_SSL_SINGLE_CIPHERSUITE is enabled) and removing the
field from mbedtls_ssl_session in this case.
If MBEDTLS_SSL_SINGLE_CIPHERSUITE is enabled, it overwrites
the runtime configuration of supported ciphersuites, which
includes both the configuration API and the fields which are
used to store the configuration. Both are therefore no longer
needed and should be removed for the benefit of code-size,
memory usage, and API clarity (no accidental hiccup of runtime
vs. compile-time configuration possible).
The configuration API mbedtls_ssl_conf_ciphersuites() has
already been removed in case MBEDTLS_SSL_SINGLE_CIPHERSUITE,
and this commit removes the field
mbedtls_ssl_config::ciphersuite_list
which it updates.
If MBEDTLS_SSL_SINGLE_CIPHERSUITE is enabled, the type
mbedtls_ssl_ciphersuite_handle_t
is logically a boolean (concretely realized as `unsigned char`),
containing the invalid handle and the unique valid handle, which
represents the single enabled ciphersuite.
The SSL handshake structure mbedtls_ssl_handshake_params contains
an instance of mbedtls_ssl_ciphersuite_handle_t which is guaranteed
to be valid, and which is hence redundant in any two-valued
implementation of mbedtls_ssl_ciphersuite_handle_t.
This commit replaces read-uses of
mbedtls_ssl_handshake_params::ciphersuite_info
by a getter functions which, and defines this getter function
either by just reading the field from the handshake structure
(in case MBEDTLS_SSL_SINGLE_CIPHERSUITE is disabled), or by
returning the single valid ciphersuite handle (in case
MBEDTLS_SSL_SINGLE_CIPHERSUITE is enabled) and removing the
field from mbedtls_ssl_handshake_params in this case.
This commit adapts the ClientHello parsing routines in ssl_srv.c
to use the ciphersuite traversal macros
MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE
MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
introduced in the last commit, thereby making them work
both with and without MBEDTLS_SSL_SINGLE_CIPHERSUITE.
Another notable change concerns the ssl_ciphersuite_match:
Previous, this function would take a ciphersuite ID and a
pointer to a destination ciphersuite info structure as input
and write eithe NULL or a valid ciphersuite info structure
to that destination address, depending on whether the suite
corresponding to the given ID was suitable or not. The
function would always return 0 outside of a fatal error.
This commit changes this to ssl_ciphersuite_is_match() which
instead already takes a ciphersuite handle (which outside
of a hardcoded ciphersuite is the same as the ptr to a
ciphersuite info structure) and returns 0 or 1 (or a
negative error code in case of a fatal error) indicating
whether the suite corresponding to the handle was acceptable
or not. The conversion of the ciphersuite ID to the ciphersuite
info structure is done prior to calling ssl_ciphersuite_is_match().
This commit modifies the ClientHello writing routine ssl_write_client_hello
in ssl_cli.c to switch between
(a) listing all runtime configured ciphersuites
(in case MBEDTLS_SSL_SINGLE_CIPHERSUITE is not defined)
(b) listing just the single hardcoded ciphersuite
(in case MBEDTLS_SSL_SINGLE_CIPHERSUITE is defined)
The approach taken is to introduce a pair of helper macros
MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl, ver, info )
MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
which when delimiting a block of code lead to that block of
code being run once for each ciphersuite that's enabled in the
context `ssl` and version `ver`, referenced through the (fresh)
`info` variable. Internally, this is implemented either through
a plain `for` loop traversing the runtime configured ciphersuite
list (if MBEDTLS_SSL_SINGLE_CIPHERSUITE is disabled) or by just
hardcoding `info` to the single enabled ciphersuite (if
MBEDTLS_SSL_SINGLE_CIPHERSUITE is enabled).
These helper macros will prove useful whereever previous code
traversed the runtime configured ciphersuite list, but adaptations
of those occasions outside ClientHello writing are left for later
commits.
This commit is a step towards the goal of allowing to hardcode the choice
of a single ciphersuite at compile-time. The hoped for benefit of this is
that whereever a ciphersuite attribute is queried and checked against a
compile-time constant, the check can be recognized as either true or false
at compile-time, hence leading to a code-size reduction.
For this to work, the ciphersuite attribute getter functions
mbedtls_ssl_suite_get_xxx() will be modified to return something
the compiler can recognize as a compile-time constant. In particular,
in order to avoid relying on constant propagation abilities of the
compiler, these functions should ideally return constant symbols
(instead of, say, fields in a globally const structure instance).
This puts us in the following situation: On the one hand, there's the
array of ciphersuite information structures defining the attribute of
those ciphersuites the stack knows about. On the other hand, we need
direct access to those fields through constant symbols in the getter
functions.
In order to avoid any duplication of information, this commit exemplifies
how ciphersuites can be conveniently defined on the basis of macro
definitions, and how the corresponding instances of the ciphersuite
information structure can be auto-generated from this.
In the approach, to add support for a ciphersuite with official name
NAME (such as TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8), the following macro
constants need to be defined in ssl_ciphersuites.h:
MBEDTLS_SUITE__ NAME __ID
MBEDTLS_SUITE__ NAME __NAME
MBEDTLS_SUITE__ NAME __CIPHER
MBEDTLS_SUITE__ NAME __MAC
...
To make check-names.sh happy, one also needs a dummy macro
MBEDTLS_SUITE__ NAME()
These ciphersuite attribute values can then be queried via
MBEDTLS_SSL_SUITE_ID( NAME_MACRO )
...
where NAME_MACRO can be any macro expanding to a defined NAME.
Further, a convenience macro
MBEDTLS_SSL_SUITE_INFO( NAME_MACRO )
is provided that again takes a macro NAME_MACRO expanding to a
defined NAME, and itself expands to an instance of
mbedtls_ssl_ciphersuite_info_t using the macro attributes
defined for NAME. This macro is then used in ssl_ciphersuites.c
when defining the array of known ciphersuite information structures,
(a) without duplicating the information, and (b) with increased
readability, because there's only one line for each ciphersuite.
This commit introduces an internal zero-cost abstraction layer for
SSL ciphersuites: Instead of addressing ciphersuites via pointers
to instances of mbedtls_ssl_ciphersuite_t and accessing their fields
directly, this commit introduces an opaque type
mbedtls_ssl_ciphersuite_handle_t,
and getter functions
mbedtls_ssl_suite_get_xxx()
operating on ciphersuite handles.
The role of NULL is played by a new macro constant
MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE
which results of functions returning handles can be checked against.
(For example, when doing a lookup of a ciphersuite from a peer-provided
ciphersuite ID in the per's Hello message).
The getter functions have the validity of the handle as a precondition
and are undefined if the handle is invalid.
So far, there's only one implementation of this abstraction layer, namely
mbedtls_ssl_ciphersuite_handle_t being mbedtls_ssl_ciphersuite_t const *
and
getter functions being field accesses.
In subsequent commits, however, the abstraction layer will be useful
to save code in the situation where only a single ciphersuite is enabled.
Previously, ssl.h included ssl_ciphersuites.h to have access to the
helper macros MBEDTLS_KEY_EXCHANGE_XXX_ENABLED, and for no other
reason. This commit moves the definitions of these macros to ssl.h,
thereby removing the dependency of ssl.h on ssl_ciphersuites.h.
So far, the client-proposed list of elliptic curves was stored for the
duration of the entire handshake in a heap-allocated buffer referenced
from mbedtls_ssl_handshake_params::curves. It is used in the following
places:
1) When the server chooses a suitable ciphersuite, it checks that
it has a certificate matching the ciphersuite; in particular, if
the ciphersuite involves ECDHE, the server needs an EC certificate
with a curve suitable for the client.
2) When performing the ECDHE key exchange, the server choose one
curve among those proposed by the client which matches the server's
own supported curve configuration.
This commit removes the hold back the entire client-side curve list
during the handshake, by performing (1) and (2) on during ClientHello
parsing, and in case of (2) only remembering the curve chosen for ECDHE
within mbedtls_ssl_handshake_params.
Fix an "unused variable" warning that happened in some configurations
(without EC, found by depend-pkalg.pl) and was not present in any parent PR
but only in the result of merging them: one of the PRs clarified the
distinction between `ret` and `verify_ret` and the other removed one
occurrence of using `ret`, and the conjunction of the two made `ret` unused in
some cases. Resolving by reducing the scope of that variable.
* restricted/pr/608:
programs: Make `make clean` clean all programs always
ssl_tls: Enable Suite B with subset of ECP curves
windows: Fix Release x64 configuration
timing: Remove redundant include file
net_sockets: Fix typo in net_would_block()
Add all.sh component that exercises invalid_param checks
Remove mbedtls_param_failed from programs
Make it easier to define MBEDTLS_PARAM_FAILED as assert
Make test suites compatible with #include <assert.h>
Pass -m32 to the linker as well
Update library to 2.16.2
Use 'config.pl baremetal' in all.sh
Clarify ChangeLog entry for fix to #1628Fix#2370, minor typos and spelling mistakes
Add Changelog entry for clang test-ref-configs.pl fix
Enable more compiler warnings in tests/Makefile
Change file scoping of test helpers.function
* restricted/pr/594:
Adapt baremetal.h and baremetal.sh
Don't incl. CAs in CertReq message in baremetal build
Allow config'n of incl of CertificateReq CA list Y/N at compile-time
Allow configuration of endpoint (cli/srv) at compile-time
Allow configuration of read timeouts at compile-time
Allow configuration of ConnectionID at compile-time
Allow compile-time configuration of legacy renegotiation
Allow compile-time configuration of authentication mode
Allow compile-time configuration of DTLS badmac limit
Allow compile-time configuration of DTLS anti replay
* restricted/pr/601: (27 commits)
Fix compile-time guard for optional field in struct
Move code to reduce probability of conflicts
Fix typos caught by check-names.sh
Clarify conditions related to resumption in client
Introduce getter function for renego_status
Add getter function for handshake->resume
Remove now-redundant code
Remove cache callbacks from config on client
Fix a few style issues
Expand documentation of new options a bit
Fix renaming oversight in documentation
Remove backticks in doxygen in config.h
Declare dependency on tickets for two ssl-opt.sh tests
Exclude new negative options from config.pl full
Restore config.h defaults
Address review comments
Fix ssl_cli resumption guards
Fix check-files, check-names and check-generated-features
Add test to all.sh
Add changelog entry
...
* restricted/pr/584: (140 commits)
Remove superfluous new line in x509.c
Add comment about X.509 name comparison of buffer with itself
[Fixup] Add missing PK release call in Cert Verify parsing
Fix guard controlling whether nested acquire calls are allowed
Add X.509 CRT test for nested calls for CRT frame / PK acquire
Don't return threading error on release()-without-acquire() calls
Don't allow nested CRT acquire()-calls if MBEDTLS_X509_ALWAYS_FLUSH
Make X.509 CRT cache reference counting unconditional
Remove memory buffer alloc from i386 test in all.sh
Don't mention pk_sign() in the context of public-key contexts
Don't use assertion for failures of mbedtls_x509_crt_x_acquire()
Fix copy pasta in x509_crt.h
Reference copy-less versions of X.509 CRT frame/PK getters
x509_crt.c: Add blank line to increase readability
[FIXUP] Fix bug in ASN.1 traversal of silently ignored tag
[FIXUP] Fix typo in declaration of mbedtls_x509_memcasecmp()
Move signature-info extraction out of MBEDTLS_X509_REMOVE_INFO
Fix certificate validity checking logic to work with !TIME_DATE
Simplify X.509 CRT version check in UID parsing
Remove unused variable warning in on-demand X.509 parsing
...
This commit modifies the baremetal configuration to disables the inclusion
of the list of accepted CAs in the CertificateRequest message sent by the
server.
Impact on code-size:
| | GCC 8.2.1 | ARMC5 5.06 | ARMC6 6.12 |
| --- | --- | --- | --- |
| `libmbedtls.a` before | 23099 | 23781 | 26639 |
| `libmbedtls.a` before | 22995 | 23689 | 26515 |
| gain in Bytes | 104 | 92 | 124 |
Introduces MBEDTLS_SSL_CONF_CERT_REQ_CA_LIST which allows to configure
at compile-time whether a CA list should be included in the
CertificateRequest message sent by the server.
Impact on code-size:
| | GCC 8.2.1 | ARMC5 5.06 | ARMC6 6.12 |
| --- | --- | --- | --- |
| `libmbedtls.a` before | 23131 | 23805 | 26673 |
| `libmbedtls.a` after | 23099 | 23781 | 26639 |
| gain in Bytes | 32 | 24 | 34 |
Introduces MBEDTLS_SSL_CONF_BADMAC_LIMIT to fix the maximum
number of records with bad MAC tolerated in DTLS at compile-time.
Impact on code-size:
| | GCC | ARMC5 | ARMC6 |
| --- | --- | --- | --- |
| `libmbedtls.a` before | 23511 | 24049 | 27903 |
| `libmbedtls.a` after | 23487 | 24025 | 27885 |
| gain in Bytes | 24 | 24 | 18 |
mbedtls_ssl_read() can fail non-fatally, in which case
ssl_parse_certificate_verify() returned immediately without
calling mbedtls_x509_crt_pk_release(), which in turn lead
to a fatal error because of nested acquire calls in the
next call to the function.
There are a number of PRs in flight that are going to append to the list of
getter functions for harcodeable SSL conf items, so leave that list at the end
in order to avoid conflicts between this PR and the SSL conf ones.
While not strictly related to this PR, this change improves readability in
some resumption-related runtime conditions that previously had rather ugly
preprocessor directives in the middle of already complex predicates.
Due to previous change of conditions, this is now in the 'else' branch of 'if
resume == 1' and the only allowed values are 0 or 1, so setting to 0 is
redundant.
The session cache is only server-side. This also aligns the conditions
guarding those fields with the condition guarding the function setting them -
no need to have the fields if we can't set them.
This preserves the API and ABI in the default config as it only affects
non-default configs.
Add a new configuration option MBEDTLS_SSL_SESSION_RESUMPTION
to enable/disable the session resumption feature including
ticket and cache based session resumption.
Resource counting as a safe-guard against nested acquire calls
is implemented if and only if MBEDTLS_X509_ALWAYS_FLUSH is disabled
_or_ MBEDTLS_THREADING_C is enabled.
Oz is allowed to make size optimizations that make the code slower,
where Os isn't. Optimize with Oz, as we care more about having a small
code footprint than having fast code.
Previously, a call to mbedtls_x509_crt_xxx_release() would return
MBEDTLS_ERR_THREADING_MUTEX_ERROR if usage counter for the frame/PK
was 0. Now that resource counting can also be used outside of
threading support, this is no longer adequate, and this commit
changes the return code to MBEDTLS_ERR_X509_FATAL_ERROR; while
generic, this at least matches the top-level module.
Forbidding nested calls to acquire() allows to remove the reference
counting logic and hence saving some bytes of code. This is valuable
because MBEDTLS_X509_ALWAYS_FLUSH is likely to be used on constrained
systems where code-size is limited.
Previously, reference counting for the CRT frames and PK contexts
handed out by mbedtls_x509_crt_{frame|pk}_acquire() was implemented
only in case threading support was enabled, which leaves the door
open for a potential use-after-free should a single-threaded application
use nested calls to mbedtls_x509_crt_acquire().
Since Mbed TLS itself does not use such nested calls, it might be
preferred long-term to forbid nesting of acquire calls on the API
level, and hence get rid of reference counting in the interest of
code-size benefits. However, this can be considered as an optimization
of X.509 on demand parsing, and for now this commit introduces
reference counting unconditionally to have a safe version of
on demand parsing to build further optimizations upon.
During rebase, the definition of ::mbedtls_x509_crt_sig_info
as well as x509_crt_free_sig_info() and x509_crt_get_sig_info()
were accidentally guarded by !MBEDTLS_X509_REMOVE_INFO.
This commit moves their definition outside of that guard.
If MBEDTLS_HAVE_TIME_DATE is undefined, the functions
`mbedtls_x509_time_is_past()` and `mbedtls_x509_time_is_future()`
are still defined but return `0` (that is, no time is seen to in
the past or future). To maintain functional correctness, this
means that these functions have to be called in a way where
the condition being checked for is the erroneous one: Concretely,
one shouldn't check that a CRT's `validFrom` is in the past,
or that its `validTo` is in the future, because that would
fail if !MBEDTLS_HAVE_TIME_DATE. Instead, one should check
that `validFrom` is NOT in the future, and `validTo` is NOT
in the past. That was the logic previously, but an uncautious
change during transition to X.509 on-demand parsing has
changed it. This commit fixes this.
WHen parsing the CRT version, we already check that
version is either 1, 2, or 3, so checking whether
version == 2 or version == 3 is equivalent to
version != 1.
The previous tests used 100 parallel workers which for EC certificates
leads to a memory usage of more than 1Mb, hence leading to an out of memory
condition in tests using the memory buffer allocator which has a pool of 1Mb.
Use 25 workers but an increased number of iterations per worker instead.
Previously, only one thread could access the parsing cache of an X.509 CRT
at a time. Firstly, this leads to significant performance penalties on
systems running many concurrent threads which share CRT structures --
for example, server threads sharing an SSL configuration containing the
server CRT. Secondly, the locking should be logically unnecessary, because
the threads are supposed to access the CRT frame and PK in a read-only,
or at least thread-safe manner.
This commit modifies the X.509 CRT cache implementation by allowing an
arbitrary number of concurrent readers, locking only the path of setting
up and clearing the cache.
This allows to build the library + tests via `make` without
specifying `PTHREAD=1`, in which case the X.509 threading
test suite will be silently dropped.
This is analogous to the pre-existing handling of the example
application `ssl_pthread_server`, which is only build if `PTHREAD=1`
and silently dropped otherwise.
The pre-existing LINK_WITH_PTHREAD CMake option controls whether
`pthread` should be linked into the library, but didn't apply
to the test suites so far.
This commit also links test suites to `pthread` in CMake-based
builds which have LINK_WITH_PTHREAD set.
This commit enhances the X.509 parsing test suite by a test
which exercises multiple threads concurrently verifying the
same certificate with the same set of trusted roots.
In contrast to mbedtls_x509_crt_frame_acquire(), the public key context
returned by mbedtls_x509_crt_pk_acquire() cannot be marked `const` because
the caller must be able to use it e.g. for mbedtls_pk_sign() and
mbedtls_pk_verify(), which don't have `const` input parameters.
Instead, return a non-`const` context, but explicitly state that callers
must use that context in a thread-safe way.
We cannot move it to x509_crt.c because there are some static inline
function definitions in x509_crt.h which access members of
mbedtls_x509_crt_cache.
This commit modifies the implementation of x509_get_ext_key_usage()
to not rely on mbedtls_asn1_get_sequence_of() but to instead use
mbedtls_asn1_traverse_sequence_of() with the same sequence-building
callback that also x509_get_subject_alt_name() uses, and which agrees
with the callback used by mbedtls_asn1_get_sequence_of().
The reason for this is that with this change, Mbed TLS itself isn't
using mbedtls_asn1_get_sequence_of() anymore, but only the more powerful
mbedtls_asn1_traverse_sequence_of(), so that unless application code
makes use of mbedtls_asn1_get_sequence_of(), its implementation
-- including the underlying sequence building callback -- will be
removed by link time garbage collection.
This commit introduces a compile-time option MBEDTLS_X509_ALWAYS_FLUSH
which controls whether releasing of CRT frames or public key contexts
associated to X.509 CRTs (or, in the future, other cached parsed X.509
structures) should lead to freeing those structures immediately.
Enabling this alongside of the MBEDTLS_X509_ON_DEMAND_PARSING leads
to significant reduction of the average RAM consumption of Mbed TLS.
The option is enabled by default to reduce the permanent RAM overhead of
MBEDTLS_X509_ON_DEMAND_PARSING in case the latter is *disabled* (default).
(Note that there is very little performance penalty enabling
MBEDTLS_X509_ALWAYS_FLUSH in case MBEDTLS_X509_ON_DEMAND_PARSING is disabled,
because hardly any parsing needs to be done to setup a CRT frame / PK context
from the legacy `mbedtls_x509_crt` structure.)
This commit introduces two static helpers
- `x509_buf_to_buf_raw()`
- `x509_buf_raw_to_buf()`
which convert to/from the old `mbedtls_x509_buf` and
the new `mbedtls_x509_buf_raw` (the latter omitting the
ASN.1 tag field).
So far, the CRT frame structure `mbedtls_x509_crt_frame` used
as `issuer_raw` and `subject_raw` the _content_ of the ASN.1
name structure for issuer resp. subject. This was in contrast
to the fields `issuer_raw` and `subject_raw` from the legacy
`mbedtls_x509_crt` structure, and caused some information
duplication by having both variants `xxx_no_hdr` and `xxx_with_hdr`
in `mbedtls_x509_crt` and `mbedtls_x509_crt_frame`.
This commit removes this mismatch by solely using the legacy
form of `issuer_raw` and `subject_raw`, i.e. those _including_
the ASN.1 name header.
Previously, `mbedtls_x509_crt_cache_provide_frame()` provided the requested
CRT frame by always parsing the raw data underlying the CRT. That's inefficient
in legacy mode, where the CRTs fields are permanently accessible through the
legacy `mbedtls_x509_crt` structure.
This commit modifies `mbedtls_x509_crt_cache_provide_frame()` in legacy mode
(that is, !MBEDTLS_X509_ON_DEMAND_PARSING) to setup the CRT frame by copying
fields from the legacy CRT structure.
This commit adds a `make test` and `ssl-opt.sh` run to `all.sh`
exercising the default configuration, plus the following changes:
- MBEDTLS_SSL_KEEP_PEER_CERTIFICATE disabled
- MBEDTLS_X509_ON_DEMAND_PARSING enabled.
This commit modifies the CRT parsing routine to flush
the CRT cache after parsing. More specifically, the
frame cache is flushed before the PK is parsed, to
avoid storing the PK and frame in RAM at the same time.
With the introduction of `mbedtls_x509_crt_get_{issuer|name}()`,
users need an easy way of freeing the dynamic name structures these
functions return.
To that end, this commit renames `x509_{sequence|name}_free()`
to `mbedtls_x509_{sequence|name}_free()` and gives them external linkage.
The legacy `mbedtls_x509_crt` contains fields `issuer/subject`
which are dynamically allocated linked list presentations of the
CRTs issuer and subject names, respectively.
The new CRT frame structure `mbedtls_x509_crt_frame`, however,
only provides pointers to the raw ASN.1 buffers for the issuer
and subject, for reasons of memory usage.
For convenience to users that previously used the `issuer`/`subject`
fields of `mbedtls_x509_crt`, this commit adds two public API functions
`mbedtls_x509_crt_get_subject()` and `mbedtls_x509_crt_get_issuer()`
which allow to request the legacy linked list presentation of the
CRTs subject / issuer names.
Similar to `mbedtls_x509_crt_get_pk()`, the returned names are owned
by the user, and must be freed through a call to `mbedtls_x509_name_free()`.
This commit unconditionally adds two convenience API functions:
- mbedtls_x509_crt_get_frame()
- mbedtls_x509_crt_get_pk()
which allow users to extract a CRT frame or PK context
from a certificate.
The difference with the existing acquire/release API for frame and PK
contexts is that in contrast to the latter, the structures returned by
the new API are owned by the user (and, in case of the PK context, need
to be freed by him). This makes the API easier to use, but comes at the
cost of additional memory overhead.
This commit replaces the dummy implementation of the CRT acquire/release
framework by a cache-based implementation which remembers frame and PK
associated to a CRT across multiple `acquire/release` pairs.
Access the peer's PK through the PK acquire/release API only.
Care has to be taken not to accidentally overwrite the return
value `ret` from the CRT chain verification.
This commit modifies the static function `x509_crt_verify_name()` to
use the acquire/release API to access the given CRTs `subject` field.
This function is solely called from the beginning of the CRT chain
verification routine, which also needs to access the child's CRT frame.
It should therefore be considered - for a later commit - to collapse
the two acquire/release pairs to one, thereby saving some code.
Previously, `mbedtls_x509_crt_der_internal()` used the `version` field
(which is `0` after initialization but strictly greater than 0 once a
CRT has successfully been parsed) to determine whether an
`mbedtls_x509_crt` instance had already been setup.
Preparating for the removal of `version` from the structure, this
commit modifies the code to instead peek at the raw data pointer,
which is NULL as long as the CRT structure hasn't been setup with a CRT,
and will be kept in the new CRT structure.
This commit adapts `mbedtls_x509_crt_info()` to no longer access
structure fields from `mbedtls_x509_crt` directly, but to instead
query for a `mbedtls_x509_crt_frame` and `mbedtls_pk_context` and
use these to extract the required CRT information.
This commit continues rewriting the CRT chain verification to use
the new acquire/release framework for CRTs. Specifically, it replaces
all member accesses of the current _parent_ CRT by accesses to the
respective frame.
This commit introduces an internal structure `mbedtls_x509_crt_sig_info`
containing all information that has to be kept from a child CRT when searching
for a potential parent:
- The issuer name
- The signature type
- The signature
- The hash of the CRT
The structure can be obtained from a CRT frame via `x509_crt_get_sig_info()`
and freed via `x509_crt_free_sig_info()`.
The purpose of this is to reduce the amount of RAM used during CRT
chain verification; once we've extracted the signature info structure
from the current child CRT, we can free all cached data for that CRT
(frame and PK) before searching for a suitable parent. This way, there
will ultimately not be more than one frame needed at a single point
during the verification.
The function `x509_crt_find_parent_in()` traverses a list of CRTs
to find a potential parent to a given CRT. So far, the logic was
the following: For each candidate,
- check basic parenting skills (mostly name match)
- verify signature
- verify validity
This order is insuitable for the new acquire/release layer of
indirection when dealing with CRTs, because we either have to
query the candidate's CRT frame twice, or query frame and PK
simultaneously.
This commit moves the validity check to the beginning of the
routine to allow querying for the frame and then for the PK.
The entry point for restartable ECC needs to be moved for that
to not forget the validity-flag while pausing ECC computations.
During CRT verification, `x509_crt_check_signature()` checks whether a
candidate parent CRT correctly signs the current child CRT.
This commit rewrites this function to use the new acquire/release
framework for using CRTs.
The goal of the subsequent commits is to remove all direct uses
of the existing `mbedtls_x509_crt` apart from the `raw` buffer
and the linked list `next` pointer.
The approach is the following: Whenever a code-path needs to inspect
a CRT, it can request a frame for the CRT through the API
`x509_crt_frame_acquire()`. On success, this function returns a pointer
to a frame structure for the CRT (the origin of which is flexible and
need not concern the caller) that can be used to inspect the desired
fields. Once done, the caller hands back the frame through an explicit
call to `x509_crt_frame_release()`.
This commit also adds an inefficient dummy implementation for
`x509_crt_frame_acquire()` which always allocates a new
`mbedtls_x509_crt_frame` structure on the heap and parses it
from the raw data underlying the CRT. This will change in subsequent
commits, but it constitutes a valid implementation to test against.
Ultimately, `x509_crt_frame_acquire()` is to compute a frame for the
given CRT only once, and cache it for subsequent calls.
The need for `x509_crt_frame_release()` is the following: When
implementing `x509_crt_frame_acquire()` through a flushable cache
as indicated above, it must be ensured that no thread destroys
a cached frame structure for the time it is needed by another
thread. The `acquire/release` pair allows to explicitly delimit
the lifetime requirements for the returned frame structure.
The frame pointer must not be used after the `release` call anymore;
and in fact, the dummy implementation shows that it would
immediately lead to a memory failure.
Analogously to `x509_crt_frame_{acquire|release}()`, there's also
`x509_crt_pk_{acquire|release}()` which allows to acquire/release
a PK context setup from the public key contained within the CRT.
This commit restructures the parsing of X.509 CRTs in the following way:
First, it introduces a 'frame' structure `mbedtls_x509_crt_frame`, which
contains pointers to some structured fields of a CRT as well as copies of
primitive fields. For example, there's a pointer-length pair delimiting the raw
public key data in the CRT, but there's a C-uint8 to store the CRT version
(not a pointer-length pair delimiting the ASN.1 structure holding the version).
Setting up a frame from a raw CRT buffer does not require any memory outside
of the frame structure itself; it's just attaches a 'template' to the buffer
that allows to inspect the structured parts of the CRT afterwards.
Note that the frame structure does not correspond to a particular ASN.1
structure; for example, it contains pointers to delimit the three parts
of a CRT (TBS, SignatureAlgorithm, Signature), but also pointers to the
fields of the TBS, and pointers into the Extensions substructure of the TBS.
Further, the commit introduces an internal function `x509_crt_parse_frame()`
which sets up a frame from a raw CRT buffer, as well as several small helper
functions which help setting up the more complex structures (Subject, Issuer, PK)
from the frame.
These functions are then put to use to rewrite the existing parsing function
`mbedtls_x509_crt_parse_der_core()` by setting up a CRT frame from the input
buffer, residing on the stack, and afterwards copying the respective fields
to the actual `mbedtls_x509_crt` structure and performing the deeper parsing
through the various helper functions.
At every occasion where we're using `mbedtls_x509_memcasecmp()` we're
checking that the two buffer lengths coincide before making the call.
This commit saves a few bytes of code by moving this length check
to `mbedtls_x509_memcasecmp()`.
This commit adds a new function `mbedtls_asn1_traverse_sequence_of()`
which traverses an ASN.1 SEQUENCE and calls a user-provided callback
for each entry.
It allows to put the following constraints on the tags allowed
in the SEQUENCE:
- A tag mask and mandatory tag value w.r.t. that mask.
A non-matching tag leads to an MBEDTLS_ERR_ASN1_UNEXPECTED_TAG error.
For example, it the mask if 0xFF, this means that only
a single tag will be allowed in the SEQUENCE.
- A tag mask and optional tag value w.r.t. that mask.
A non-matching tag is silently ignored.
The main use for this flexibility is the traversal of the
`SubjectAlternativeNames` extension, where some parts of the
tag are fixed but some are flexible to indicate which type
of name the entry describes.
This commit adds a callback for use with `x509_subject_alt_name_traverse()`
which builds the legacy dynamically allocated linked list presentation
of the `SubjectAlternativeNames` extension while traversing the raw data.
The current CN name verification x509_crt_verify_name() traverses
the dynamically allocated linked list presentation of the subject
alternative name extension, searching for an alternative name that
matches the desired hostname configured by the application.
Eventually, we want to remove this dynamically allocated linked list
for the benefit of reduced code size and RAM usage, and hence need to
rewrite x509_crt_verify_name() in a way that builds on the raw ASN.1
buffer holding the SubjectAlternativeNames extension.
This commit does this by using the existing SubjectAlternativeNames
traversal routine x509_subject_alt_name_traverse(), passing to it a
callback which compares the current alternative name component to the
desired hostname configured by the application.
This commit adds a new function `x509_subject_alt_name_traverse()`
which allows to traverse the raw ASN.1 data of a `SubjectAlternativeNames`
extension.
The `SubjectAlternativeNames` extension needs to be traversed
in the following situations:
1 Initial traversal to check well-formedness of ASN.1 data
2 Traversal to check for a particular name component
3 Building the legacy linked list presentation
Analogously to how multiple tasks related to X.509 name comparison
are implemented through the workhorse `mbedtlS_x509_name_cmp_raw()`,
the new function `x509_subject_alt_name_traverse()` allows to pass
an arbitrary callback which is called on any component of the
`SubjectAlternativeNames` extension found. This way, the above
three tasks can be implemented by passing
1 a NULL callback,
2 a name comparison callback
3 a linked list building callback.
In preparation for rewriting the `SubjectAlternativeName` search routine
to use raw ASN.1 data, this commit changes `x509_check_wildcard()` and
`x509_check_cn()`, responsible for checking whether a name matches a
wildcard pattern, to take a raw buffer pointer and length as parameters
instead of an `mbedtls_x509_buf` instance.
This is analogous to a previous commit for the `ExtendedKeyUsage`
extension: We aim at not using dynamically allocated linked lists
to represent the components of the `SubjectAlternativeName` extension,
but to traverse the raw ASN.1 data when needed.
This commit adds a field to `mbedtls_x509_crt` containing the raw
ASN.1 buffer bounds of the `SubjectAlternativeNames` extension.
This commit re-implements `mbedtls_x509_crt_check_extended_key_usage()`
to not use the dynamically allocated linked list presentation of the
`ExtendedKeyUsage` but to search for the required usage by traversing
the raw ASN.1 data.
The previous commits replace the use of dynamically allocated linked lists
for X.509 name inspection. This commit is the first in a series which attempts
the same for the `ExtendedKeyUsage` extension. So far, when a CRT is parsed,
the extension is traversed and converted into a dynamically allocated linked
list, which is then search through whenever the usage of a CRT needs to be
checked through `mbedtls_x509_check_extended_key_usage()`.
As a first step, this commit introduces a raw buffer holding the bounds
of the `ExtendedKeyUsage` extension to the `mbedtls_x509_crt` structure.
The previous CN name comparison function x509_crt_verify_name()
traversed the dynamically allocated linked list presentation of
the CRT's subject, comparing each entry to the desired hostname
configured by the application code.
Eventually, we want to get rid of the linked list presentation of
the CRT's subject to save both code and RAM usage, and hence need
to rewrite the CN verification routine in a way that builds on the
raw ASN.1 subject data only.
In order to avoid duplicating the code for the parsing of the nested
ASN.1 name structure, this commit performs the name search by using
the existing name traversal function mbedtls_x509_name_cmp_raw(),
passing to it a callback which checks whether the current name
component matches the desired hostname.
There are three operations that need to be performed on an X.509 name:
1 Initial traversal to check well-formedness of the ASN.1 structure.
2 Comparison between two X.509 name sequences.
3 Checking whether an X.509 name matches a client's ServerName request.
Each of these tasks involves traversing the nested ASN.1 structure,
In the interest of saving code, we aim to provide a single function
which can perform all of the above tasks.
The existing comparison function is already suitable not only for task 2,
but also for 1: One can simply pass two equal ASN.1 name buffers, in which
case the function will succeed if and only if that buffer is a well-formed
ASN.1 name.
This commit further adds a callback to `mbedtls_x509_name_cmp_raw()` which
is called after each successful step in the simultaneous name traversal and
comparison; it may perform any operation on the current name and potentially
signal that the comparison should be aborted.
With that, task 3 can be implemented by passing equal names and a callback
which aborts as soon as it finds the desired name component.
This commit replaces the previous calls to `mbedtls_x509_name_cmp()`
during CRT verification (to match child and parent, to check whether
a CRT is self-issued, and to match CRLs and CAs) by calls to the new
`mbedtls_x509_name_cmp_raw()` using the raw ASN.1 data; it passes the
raw buffers introduced in the last commits.
The previous name comparison function mbedtls_x509_name_cmp() is now
both unused and unneeded, and is removed.
To make use of the X.509 name comparison function based on raw
ASN.1 data that was introduced in the previous commit, this commit
adds an ASN.1 buffer field `issuer_raw_no_hdr` to `mbedtls_x509_crl`
which delimits the raw contents of the CRLs `Issuer` field.
The previous field `issuer_raw` isn't suitable for that because
it includes the ASN.1 header.
This commit provides a new function `mbedtls_x509_name_cmp_raw()`
to x509.c for comparing to X.509 names by traversing the raw ASN.1
data (as opposed to using the dynamically allocated linked list
of `mbedtls_x509_name` structures). It has external linkage because
it will be needed in `x509_crt` and `x509_crl`, but is marked
internal and hence not part of the public API.
The function `mbedtls_x509_sig_alg_gets()` previously needed the
raw ASN.1 OID string even though it is implicit in the PK and MD
parameters.
This commit modifies `mbedtls_x509_sig_alg_gets()` to infer the OID
and remove it from the parameters.
This will be needed for the new X.509 CRT structure which will
likely not store the signature OID.
Care has to be taken to handle the case of RSASSA-PSS correctly,
where the hash algorithm in the OID list is set to MBEDTLS_MD_NONE
because it's only determined by the algorithm parameters.
The previous code
- checked that at least 1 byte of ASN.1 tag data is available,
- read and stored that ASN.1 tag,
- called the ASN.1 parsing function, part of which is checking
that enough space is available and that the ASN.1 tag matches
the expected value MBEDTLS_ASN1_OID.
Since the ASN.1 parsing function includes bounds checks,
this can be streamlined to:
- call the ASN.1 parsing function directly,
- on success, store MBEDTLS_ASN1_OID in the tag field.
This commit applies this simplification to mbedtls_asn1_get_alg().
Consider the following code-template:
int beef();
static int foo()
{
/* ... */
ret = beef();
if( ret != 0 )
return( ret + HIGH_LEVEL );
/* ... */
}
int bar()
{
/* ... */
ret = foo();
if( ret != 0 )
...
/* ... */
}
This leads to slightly larger code than expected, because when the
compiler inlines foo() into bar(), the sequence of return sequences
cannot be squashed, because compiler might not have knowledge that
the wrapping `ret + HIGH_LEVEL` of the return value of beef() doesn't
lead to foo() returning 0.
This can be avoided by performing error code wrapping in nested
functions calls at the top of the call chain.
This commit applies this slight optimization to mbedtls_x509_get_name().
It also moves various return statements into a single exit section,
again with the intend to save code.
X.509 names in ASN.1 are encoded as ASN.1 SEQUENCEs of ASN.1 SETs
of Attribute-Value pairs, one for each component in the name. (For
example, there could be an Attribute-Value pair for "DN=www.mbedtls.org").
So far, `mbedtls_x509_get_name()` parsed such names by two nested
loops, the outer one traversing the outer ASN.1 SEQUENCE and the
inner one the ASN.1 SETs.
This commit introduces a helper function `x509_set_sequence_iterate()`
which implements an iterator through an ASN.1 name buffer; the state
of the iterator is a triple consisting of
- the current read pointer
- the end of the current SET
- the end of the name buffer
The iteration step reads a new SET if the current read pointer has
reached the end of the current SET, and afterwards reads the next
AttributeValue pair.
This way, iteration through the X.509 name data can be implemented
in a single loop, which increases readability and slightly reduces
the code-size.
This commit introduces a macro `MBEDTLS_ASN1_IS_STRING_TAG`
that can be used to check if an ASN.1 tag is among the list
of string tags:
- MBEDTLS_ASN1_BMP_STRING
- MBEDTLS_ASN1_UTF8_STRING
- MBEDTLS_ASN1_T61_STRING
- MBEDTLS_ASN1_IA5_STRING
- MBEDTLS_ASN1_UNIVERSAL_STRING
- MBEDTLS_ASN1_PRINTABLE_STRING
- MBEDTLS_ASN1_BIT_STRING
`x509_get_attr_type_value()` checks for the presence of a tag byte
and reads and stores it before calling `mbedtls_asn1_get_tag()` which
fails if either the tag byte is not present or not as expected. Therefore,
the manual check can be removed and left to `mbedtls_asn1_get_tag()`, and
the tag can be hardcoded after the call succeeded. This saves a few bytes
of code.
The server-side routine `ssl_pick_cert()` is responsible for
picking a suitable CRT from the list of CRTs configured on the
server. For that, it previously used the public key context
from the certificate to check whether its type (including the
curve type for ECC keys) suits the ciphersuite and the client's
preferences.
This commit changes the code to instead use the PK context
holding the corresponding private key. For inferring the type
of the key, this makes no difference, and it removes a PK-from-CRT
extraction step which, if CRTs are stored raw, is costly in terms
of computation and memory: CRTs need to be parsed, and memory needs
to be allocated for the PK context.
The server-side routine `ssl_decrypt_encrypted_pms()` is
responsible for decrypting the RSA-encrypted PMS in case of
an RSA-based ciphersuite.
Previously, the code checked that the length of the PMS sent
by the client matches the bit length of the RSA key. This commit
removes this check -- thereby removing the need to access the
server's own CRT -- because the RSA decryption routine performs
this check itself, too.
`mbedtls_x509_name` and `mbedtls_x509_sequence` are dynamically allocated
linked lists that need a loop to free properly. Introduce a static helper
function to do that and use it in `mbedtls_x509_crt_free()`, where the
CRT's issuer and subject names (of type `mbedtls_x509_name`) and the
SubjectAlternativeName and ExtendedKeyUsage extensions (of type
`mbedtls_x509_sequence`) need freeing. Increases code-clarity and saves
a few bytes of flash.
If the ExtendedMasterSecret extension is configured at compile-time
by setting MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET and/or
MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET, the runtime
configuration APIs mbedtls_ssl_conf_extended_master_secret()
and mbedtls_ssl_conf_extended_master_secret_enforce() must
either be removed or modified to take no effect (or at most
check that the runtime value matches the hardcoded one, but
that would undermine the code-size benefits the hardcoding
is supposed to bring in the first place).
Previously, the API was kept but modified to have no effect.
While convenient for us because we don't have to adapt example
applications, this comes at the danger of users calling the runtime
configuration API, forgetting that the respective fields are
potentially already hardcoded at compile-time - and hence silently
using a configuration they don't intend to use.
This commit changes the approach to removing the configuration
API in case the respective field is hardcoded at compile-time,
and exemplifies it in the only case implemented so far, namely
the configuration of the ExtendedMasterSecret extension.
It adapts ssl_client2 and ssl_server2 by omitting the call to
the corresponding API if MBEDTLS_SSL_CONF_XXX are defined and
removing the command line parameters for the runtime configuration
of the ExtendedMasterSecret extension.
`mbedtls_ssl_handshake_params::extended_ms` holds the state of the
ExtendedMasterSecret extension in the current handshake. Initially
set to 'disabled' for both client and server,
- the client sets it to 'enabled' as soon as it finds the ExtendedMS
extension in the `ServerHello` and it has advertised that extension
in its ClientHello,
- the server sets it to 'enabled' as soon as it finds the ExtendedMS
extension in the `ClientHello` and is willing to advertise is in its
`ServerHello`.
This commit slightly restructures this logic in prepraration for the
removal of `mbedtls_ssl_handshake_params::extended_ms` in case both
the use and the enforcement of the ExtendedMasterSecret extension have
been fixed at compile-time. Namely, in this case there is no need for
the `extended_ms` field in the handshake structure, as the ExtendedMS
must be in use if the handshake progresses beyond the Hello stage.
Paving the way for the removal of mbedtls_ssl_handshake_params::extended_ms
this commit introduces a temporary variable tracking the presence of the
ExtendedMS extension in the ClientHello/ServerHello messages, leaving
the derivation of `extended_ms` (and potential failure) to the end of
the parsing routine.
This commit is the first in a series demonstrating how code-size
can be reduced by hardcoding parts of the SSL configuration at
compile-time, focusing on the example of the configuration of
the ExtendedMasterSecret extension.
The flexibility of an SSL configuration defined a runtime vs.
compile-time is necessary for the use of Mbed TLS as a
dynamically linked library, but is undesirable in constrained
environments because it introduces the following overhead:
- Definition of SSL configuration API (code-size overhead)
(and on the application-side: The API needs to be called)
- Additional fields in the SSL configuration (RAM overhead,
and potentially code-size overhead if structures grow
beyond immediate-offset bounds).
- Dereferencing is needed to obtain configuration settings.
- Code contains branches and potentially additional structure
fields to distinguish between different configurations.
Considering the example of the ExtendedMasterSecret extension,
this instantiates as follows:
- mbedtls_ssl_conf_extended_master_secret() and
mbedtls_ssl_conf_extended_master_secret_enforced()
are introduced to configure the ExtendedMasterSecret extension.
- mbedtls_ssl_config contains bitflags `extended_ms` and
`enforce_extended_master_secret` reflecting the runtime
configuration of the ExtendedMasterSecret extension.
- Whenever we need to access these fields, we need a chain
of dereferences `ssl->conf->extended_ms`.
- Determining whether Client/Server should write the
ExtendedMasterSecret extension needs a branch
depending on `extended_ms`, and the state of the
ExtendedMasterSecret negotiation needs to be stored in a new
handshake-local variable mbedtls_ssl_handshake_params::extended_ms.
Finally (that's the point of ExtendedMasterSecret) key derivation
depends on this handshake-local state of ExtendedMasterSecret.
All this is unnecessary if it is known at compile-time that the
ExtendedMasterSecret extension is used and enforced:
- No API calls are necessary because the configuration is fixed
at compile-time.
- No SSL config fields are necessary because there are corresponding
compile-time constants instead.
- Accordingly, no dereferences for field accesses are necessary,
and these accesses can instead be replaced by the corresponding
compile-time constants.
- Branches can be eliminated at compile-time because the compiler
knows the configuration. Also, specifically for the ExtendedMasterSecret
extension, the field `extended_ms` in the handshake structure
is unnecessary, because we can fail immediately during the Hello-
stage of the handshake if the ExtendedMasterSecret extension
is not negotiated; accordingly, the non-ExtendedMS code-path
can be eliminated from the key derivation logic.
A way needs to be found to allow fixing parts of the SSL configuration
at compile-time which removes this overhead in case it is used,
while at the same time maintaining readability and backwards
compatibility.
This commit proposes the following approach:
From the user perspective, for aspect of the SSL configuration
mbedtls_ssl_config that should be configurable at compile-time,
introduce a compile-time option MBEDTLS_SSL_CONF_FIELD_NAME.
If this option is not defined, the field is kept and configurable
at runtime as usual. If the option is defined, the field is logically
forced to the value of the option at compile time.
Internally, read-access to fields in the SSL configuration which are
configurable at compile-time gets replaced by new `static inline` getter
functions which evaluate to the corresponding field access or to the
constant MBEDTLS_SSL_CONF_FIELD_NAME, depending on whether the latter
is defined or not.
Write-access to fields which are configurable at compile-time needs
to be removed: Specifically, the corresponding API itself either
needs to be removed or replaced by a stub function without effect.
This commit takes the latter approach, which has the benefit of
not requiring any change on the example applications, but introducing
the risk of mismatching API calls and compile-time configuration,
in case a user doesn't correctly keep track of which parts of the
configuration have been fixed at compile-time, and which haven't.
Write-access for the purpose of setting defaults is simply omitted.
If `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` is not set, `mbedtls_ssl_session`
contains the digest of the peer's certificate for the sole purpose of
detecting a CRT change on renegotiation. Hence, it is not needed if
renegotiation is disabled.
This commit removes the `peer_cert_digest` fields (and friends) from
`mbedtls_ssl_session` if
`!MBEDTLS_SSL_KEEP_PEER_CERTIFICATE + !MBEDTLS_SSL_RENEGOTIATION`,
which is a sensible configuration for constrained devices.
Apart from straightforward replacements of
`if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)`
by
`if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) && \
defined(MBEDTLS_SSL_RENEGOTIATION)`,
there's one notable change: On the server-side, the CertificateVerify
parsing function is a no-op if the client hasn't sent a certificate.
So far, this was determined by either looking at the peer CRT or the
peer CRT digest in the SSL session structure (depending on the setting
of `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE`), which now no longer works if
`MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` is unset. Instead, this function
now checks whether the temporary copy of the peer's public key within
the handshake structure is initialized or not (which is also a
beneficial simplification in its own right, because the pubkey is
all the function needs anyway).
The previous placing of the return statement made it look like there
are configurations for which no return statement is emitted; while
that's not true (if this function is used, at least some version of
TLS must be enabled), it's still clearer to move the failing return
statement to outside of all preprocessor guards.
So far, `ssl_client2` printed the CRT info for the peer's CRT
by requesting the latter through `mbedtls_ssl_get_peer_cert()`
at the end of the handshake, and printing it via
`mbedtls_x509_crt_info()`. When `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE`
is disabled, this does no longer work because the peer's CRT
isn't stored beyond the handshake.
This makes some tests in `ssl-opt.sh` fail which rely on the CRT
info output for the peer certificate.
This commit modifies `ssl_client2` to extract the peer CRT info
from the verification callback, which is always called at a time
when the peer's CRT is available. This way, the peer's CRT info
is still printed if `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` is disabled.
`MBEDTLS_SSL__ECP_RESTARTABLE` is only defined if
`MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED` is set, which
requires `MBEDTLS_X509_PARSE_C` to be set (this is checked
in `check_config.`). The additional `MBEDTLS_X509_PARSE_C`
guard around the `ecrs_peer_cert` field is therefore not
necessary; moreover, it's misleading, because it hasn't
been used consistently throughout the code.
If we don't need to store the peer's CRT chain permanently, we may
free it immediately after verifying it. Moreover, since we parse the
CRT chain in-place from the input buffer in this case, pointers from
the CRT structure remain valid after freeing the structure, and we
use that to extract the digest and pubkey from the CRT after freeing
the structure.
It is used in `mbedtls_ssl_session_free()` under
`MBEDTLS_X509_CRT_PARSE_C`, but defined only if
`MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED`.
Issue #2422 tracks the use of
`MBEDTLS_KEY_EXCHANGE__WITH_CERT_ENABLED` instead of
`MBEDTLS_X509_CRT_PARSE_C` for code and fields
related to CRT-based ciphersuites.
The server expects a CertificateVerify message only if it has
previously received a Certificate from the client.
So far, this was detected by looking at the `peer_cert` field
in the current session. Preparing to remove the latter, this
commit changes this to instead determine the presence of a peer
certificate by checking the new `peer_cert_digest` pointer.
We must dispatch between the peer's public key stored as part of
the peer's CRT in the current session structure (situation until
now, and future behaviour if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is
enabled), and the sole public key stored in the handshake structure
(new, if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled).
We must dispatch between the peer's public key stored as part of
the peer's CRT in the current session structure (situation until
now, and future behaviour if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is
enabled), and the sole public key stored in the handshake structure
(new, if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled).
We must dispatch between the peer's public key stored as part of
the peer's CRT in the current session structure (situation until
now, and future behaviour if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is
enabled), and the sole public key stored in the handshake structure
(new, if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled).
We must dispatch between the peer's public key stored as part of
the peer's CRT in the current session structure (situation until
now, and future behaviour if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is
enabled), and the sole public key stored in the handshake structure
(new, if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled).
This commit modifies `mbedtls_ssl_parse_certificate()` to store a
copy of the peer's public key after parsing and verifying the peer's
CRT chain.
So far, this leads to heavy memory duplication: We have the CRT chain
in the I/O buffer, then parse (and, thereby, copy) it to a
`mbedtls_x509_crt` structure, and then make another copy of the
peer's public key, plus the overhead from the MPI and ECP structures.
This inefficiency will soon go away to a significant extend, because:
- Another PR adds functionality to parse CRTs without taking
ownership of the input buffers. Applying this here will allow
parsing and verifying the peer's chain without making an additional
raw copy. The overhead reduces to the size of `mbedtls_x509_crt`,
the public key, and the DN structures referenced in the CRT.
- Once copyless parsing is in place and the removal of the peer CRT
is fully implemented, we can extract the public key bounds from
the parsed certificate and then free the entire chain before
parsing the public key again. This means that we never store
the parsed public key twice at the same time.
When removing the (session-local) copy of the peer's CRT chain, we must
keep a handshake-local copy of the peer's public key, as (naturally) every
key exchange will make use of that public key at some point to verify that
the peer actually owns the corresponding private key (e.g., verify signatures
from ServerKeyExchange or CertificateVerify, or encrypt a PMS in a RSA-based
exchange, or extract static (EC)DH parameters).
This commit adds a PK context field `peer_pubkey` to the handshake parameter
structure `mbedtls_handshake_params_init()` and adapts the init and free
functions accordingly. It does not yet make actual use of the new field.
This commit adds an ASN.1 buffer field `pk_raw` to `mbedtls_x509_crt`
which stores the bounds of the raw public key data within an X.509 CRT.
This will be useful in subsequent commits to extract the peer's public
key from its certificate chain.
This commit changes the format of session tickets to include
the digest of the peer's CRT if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
is disabled.
This commit does not yet remove the peer CRT itself.
`mbedtls_ssl_parse_certificate()` parses the peer's certificate chain
directly into the `peer_cert` field of the `mbedtls_ssl_session`
structure being established. To allow to optionally remove this field
from the session structure, this commit changes this to parse the peer's
chain into a local variable instead first, which can then either be freed
after CRT verification - in case the chain should not be stored - or
mapped to the `peer_cert` if it should be kept. For now, only the latter
is implemented.
mbedtls_ssl_parse_certificate() will fail if a ciphersuite requires
a certificate, but none is provided. While it is sensible to double-
check this, failure should be reported as an internal error and not
as an unexpected message.
A subsequent commit will need this function in the session ticket
and session cache implementations. As the latter are server-side,
this commit also removes the MBEDTLS_SSL_CLI_C guard.
For now, the function is declared in ssl_internal.h and hence not
part of the public API.
This commit modifies the helper `ssl_parse_certificate_chain()` to
accep any target X.509 CRT chain instead of hardcoding it to
`session_negotiate->peer_cert`. This increases modularity and paves
the way towards removing `mbedtls_ssl_session::peer_cert`.
This commit simplifies the client-side code for outgoing CertificateVerify
messages, and server-side code for outgoing CertificateRequest messages and
incoming CertificateVerify messages, through the use of the macro
`MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED`
indicating whether a ciphersuite allowing CertificateRequest messages
is enabled in the configuration, as well as the helper function
`mbedtls_ssl_ciphersuite_cert_req_allowed()`
indicating whether a particular ciphersuite allows CertificateRequest
messages.
These were already used in the client-side code to simplify the
parsing functions for CertificateRequest messages.
This commit adds a helper function `ssl_parse_certificate_coordinate()`
which checks whether a `Certificate` message is expected from the peer.
The logic is the following:
- For ciphersuites which don't use server-side CRTs, no Certificate
message is expected (neither for the server, nor the client).
- On the server, no client certificate is expected in the following cases:
* The server server didn't request a Certificate, which is controlled
by the `authmode` setting.
* A RSA-PSK suite is used; this is the only suite using server CRTs
but not allowing client-side authentication.
This commit introduces a static helper function
`mbedtls_ssl_ciphersuite_uses_srv_cert()`
which determines whether a ciphersuite may make use of server-side CRTs.
This function is in turn uses in `mbedtls_ssl_parse_certificate()` to
skip certificate parsing for ciphersuites which don't involve CRTs.
Note: Ciphersuites not using server-side CRTs don't allow client-side CRTs
either, so it is safe to guard `mbedtls_ssl_{parse/write}_certificate()`
this way.
Note: Previously, the code uses a positive check over the suites
- MBEDTLS_KEY_EXCHANGE_PSK
- MBEDTLS_KEY_EXCHANGE_DHE_PSK
- MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
- MBEDTLS_KEY_EXCHANGE_ECJPAKE,
while now, it uses a negative check over `mbedtls_ssl_ciphersuite_uses_srv_cert()`,
which checks for the suites
- MBEDTLS_KEY_EXCHANGE_RSA
- MBEDTLS_KEY_EXCHANGE_RSA_PSK
- MBEDTLS_KEY_EXCHANGE_DHE_RSA
- MBEDTLS_KEY_EXCHANGE_ECDH_RSA
- MBEDTLS_KEY_EXCHANGE_ECDHE_RSA
- MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA
- MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
This is equivalent since, together, those are all ciphersuites.
Quoting ssl_ciphersuites.h:
```
typedef enum {
MBEDTLS_KEY_EXCHANGE_NONE = 0,
MBEDTLS_KEY_EXCHANGE_RSA,
MBEDTLS_KEY_EXCHANGE_DHE_RSA,
MBEDTLS_KEY_EXCHANGE_ECDHE_RSA,
MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
MBEDTLS_KEY_EXCHANGE_PSK,
MBEDTLS_KEY_EXCHANGE_DHE_PSK,
MBEDTLS_KEY_EXCHANGE_RSA_PSK,
MBEDTLS_KEY_EXCHANGE_ECDHE_PSK,
MBEDTLS_KEY_EXCHANGE_ECDH_RSA,
MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA,
MBEDTLS_KEY_EXCHANGE_ECJPAKE,
} mbedtls_key_exchange_type_t;
```
The handler `mbedtls_ssl_parse_certificate()` for incoming `Certificate`
messages contains many branches updating the handshake state. For easier
reasoning about state evolution, this commit introduces a single code-path
updating the state machine at the end of `mbedtls_ssl_parse_certificate()`.
If an attempt for session resumption fails, the `session_negotiate` structure
might be partially filled, and in particular already contain a peer certificate
structure. This certificate structure needs to be freed before parsing the
certificate sent in the `Certificate` message.
This commit moves the code-path taking care of this from the helper
function `ssl_parse_certificate_chain()`, whose purpose should be parsing
only, to the top-level handler `mbedtls_ssl_parse_certificate()`.
The fact that we don't know the state of `ssl->session_negotiate` after
a failed attempt for session resumption is undesirable, and a separate
issue #2414 has been opened to improve on this.
This commit introduces a server-side static helper function
`ssl_srv_check_client_no_crt_notification()`, which checks if
the message we received during the incoming certificate state
notifies the server of the lack of certificate on the client.
For SSLv3, such a notification comes as a specific alert,
while for all other TLS versions, it comes as a `Certificate`
handshake message with an empty CRT list.
So far, we've used the `peer_cert` pointer to detect whether
we're parsing the first CRT, but that will soon be removed
if `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` is unset.
This commit introduces a helper function `ssl_clear_peer_cert()`
which frees all data related to the peer's certificate from an
`mbedtls_ssl_session` structure. Currently, this is the peer's
certificate itself, while eventually, it'll be its digest only.
After mitigating the 'triple handshake attack' by checking that
the peer's end-CRT didn't change during renegotation, the current
code avoids re-parsing the CRT by moving the CRT-pointer from the
old session to the new one. While efficient, this will no longer
work once only the hash of the peer's CRT is stored beyond the
handshake.
This commit removes the code-path moving the old CRT, and instead
frees the entire peer CRT chain from the initial handshake as soon
as the 'triple handshake attack' protection has completed.
Previously, a test exercising the X.509 CRT parser's behaviour
on unexpected tags would use a '00' byte in place of the tag
for the expected structure. This makes reviewing the examples
harder because the binary data isn't valid DER-encoded ASN.1.
This commit uses the ASN.1 NULL TLV '05 00' to test invalid
tags, and adapts surrounding structures' length values accordingly.
This eases reviewing because now the ASN.1 structures are still
well-formed at the place where the mismatch occurs.
Multiple tests in ssl-opt.sh grep for debug output that's omitted
if MBEDTLS_X509_REMOVE_INFO is defined. This commit modifies ssl-opt.sh
to skip those tests in this case.
Introduce MBEDTLS_X509_INFO to indicate the availability of the
mbedtls_x509_*_info() function and closely related APIs. When this is
not defined, also omit name and description from
mbedtls_oid_descriptor_t, and omit OID arrays, macros, and types that
are entirely unused. This saves several KB of code space.
Change-Id: I056312613379890e0d70e1d08c34171287c0aa17
In a reduced configuration without PEM, PKCS5 or PKCS12, armc5 found that ret
was set but not used. Fixing that lead to a new warning about the variable not
being used at all. Now the variable is only declared when it's needed.
Only effective together with --rom, makes two changes:
- abort in case of build warnings
- skip writing statistics
The goal is to make sure we build cleanly in the configuration used for
measuring code size, with all the compilers we use, both because we care about
that configuration and those compilers, and because any warnings would cast a
shadow on the code size measurements.
Currently the build fails with armc5 due to a pre-existing warning in PK, this
will be fixed in the next commit.
The next commit will also add an all.sh component to make sure we have no
regression in the future. (Which is the motivation for --check skipping
statistics: an all.sh component should probably not leave files around.)
While at it, fix two things:
1. The call to gcc --version was redundant with the echo line below
2. WARNING_CFLAGS shouldn't be overriden with armclang, as it would remove the
-Wall -Wextra and any directory-specific warning (such as
-Wdeclaration-after-statement in library). It's meant to be overriden only
with compilers that don't accept the default value (namely armc5 here).
Some TLS-only code paths were not protected by an #ifdef and while some
compiler are happy to just silently remove them, armc5 complains:
Warning: #111-D: statement is unreachable
Let's make armc5 happy.
This is enabled by default as we generally enable things by default unless
there's a reason not to (experimental, deprecated, security risk).
We need a compile-time option because, even though the functions themselves
can be easily garbage-collected by the linker, implementing them will require
saving 64 bytes of Client/ServerHello.random values after the handshake, that
would otherwise not be needed, and people who don't need this feature
shouldn't have to pay the price of increased RAM usage.
A positive option looks better, but comes with the following compatibility
issue: people using a custom config.h that is not based on the default
config.h and need TLS support would need to manually change their config in
order to still get TLS.
Work around that by making the public option negative. Internally the positive
option is used, though.
In the future (when preparing the next major version), we might want to switch
back to a positive option as this would be more consistent with other options
we have.
This commit modifies `scripts/baremetal.sh` to print the total code-size
of the SSL, X.509 and Crypto libraries are runs of
- ./scripts/baremetal.sh --rom --gcc
- ./scripts/baremetal.sh --rom --armc5
- ./scripts/baremetal.sh --rom --armc6
This eases quick investigation of the effect of changes on code-size.
This commit handles occurrences of case 2 and 3 in the following list:
1. Some DTLS-specific code with no TLS-specific code (most frequent)
2. Some specific code for each protocol
3. Some TLS-specific code with no DTLS-specific code (least frequent)
Case 3 previously had a weird structure in that the TLS-specific code was
always present, but the if structure was conditional on DTLS being enabled.
This is changed by this commit to a more logical structure where both the code
and the test are conditional on TLS being enabled.
Case 2 doesn't require any change in the code structure in general. However,
there is one occurrence where the if/else structure is simplified to assigning
the result of a boolean operation, and one occurrence where I also noticed a
useless use of `ssl_ep_len()` in a TLS-specific branch, that I turned to the
constant 0 as it makes more sense.
Case 1 will be handled in the next commit, as it can easily be handled in an
automated way - only cases 2 and 3 (sometimes) required manual intervention.
The list of occurrences for cases 2 and 3 was established manually by looking
for occurrences of '= MBEDTLS_SSL_TRANSPORT_' in the code and manually
checking if there was a TLS-specific branch.
New sizes (see previous commit for the measuring script):
```
both
text data bss dec hex filename
1820 0 4 1824 720 debug.o (ex library/libmbedtls.a)
0 0 0 0 0 net_sockets.o (ex library/libmbedtls.a)
548 0 0 548 224 ssl_cache.o (ex library/libmbedtls.a)
11155 0 596 11751 2de7 ssl_ciphersuites.o (ex library/libmbedtls.a)
17156 0 0 17156 4304 ssl_cli.o (ex library/libmbedtls.a)
460 0 0 460 1cc ssl_cookie.o (ex library/libmbedtls.a)
17649 0 0 17649 44f1 ssl_srv.o (ex library/libmbedtls.a)
800 0 0 800 320 ssl_ticket.o (ex library/libmbedtls.a)
39286 60 0 39346 99b2 ssl_tls.o (ex library/libmbedtls.a)
88874 60 600 89534 15dbe (TOTALS)
DTLS-only
text data bss dec hex filename
1820 0 4 1824 720 debug.o (ex library/libmbedtls.a)
0 0 0 0 0 net_sockets.o (ex library/libmbedtls.a)
548 0 0 548 224 ssl_cache.o (ex library/libmbedtls.a)
11155 0 596 11751 2de7 ssl_ciphersuites.o (ex library/libmbedtls.a)
17068 0 0 17068 42ac ssl_cli.o (ex library/libmbedtls.a)
460 0 0 460 1cc ssl_cookie.o (ex library/libmbedtls.a)
17553 0 0 17553 4491 ssl_srv.o (ex library/libmbedtls.a)
800 0 0 800 320 ssl_ticket.o (ex library/libmbedtls.a)
38499 60 0 38559 969f ssl_tls.o (ex library/libmbedtls.a)
87903 60 600 88563 159f3 (TOTALS)
TLS-only
text data bss dec hex filename
1820 0 4 1824 720 debug.o (ex library/libmbedtls.a)
0 0 0 0 0 net_sockets.o (ex library/libmbedtls.a)
548 0 0 548 224 ssl_cache.o (ex library/libmbedtls.a)
11155 0 596 11751 2de7 ssl_ciphersuites.o (ex library/libmbedtls.a)
14912 0 0 14912 3a40 ssl_cli.o (ex library/libmbedtls.a)
460 0 0 460 1cc ssl_cookie.o (ex library/libmbedtls.a)
15868 0 0 15868 3dfc ssl_srv.o (ex library/libmbedtls.a)
800 0 0 800 320 ssl_ticket.o (ex library/libmbedtls.a)
27619 60 0 27679 6c1f ssl_tls.o (ex library/libmbedtls.a)
73182 60 600 73842 12072 (TOTALS)
```
And use those tools in a few places. For now the purpose is just to validate
those tools before using them in all occurrences of transport-specific code.
The effect of these changes was measured with the following script:
```
set -eu
build() {
printf "\n$1\n"
CC=arm-none-eabi-gcc CFLAGS='-Werror -Os -march=armv6-m -mthumb' \
AR=arm-none-eabi-ar LD=arm-none-eabi-ld make clean lib >/dev/null
arm-none-eabi-size -t library/libmbedtls.a
}
git checkout -- include/mbedtls/config.h
scripts/config.pl unset MBEDTLS_NET_C
scripts/config.pl unset MBEDTLS_TIMING_C
scripts/config.pl unset MBEDTLS_FS_IO
scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
build "both"
scripts/config.pl unset MBEDTLS_SSL_PROTO_TLS
build "DTLS-only"
scripts/config.pl set MBEDTLS_SSL_PROTO_TLS
scripts/config.pl unset MBEDTLS_SSL_PROTO_DTLS
scripts/config.pl unset MBEDTLS_SSL_DTLS_HELLO_VERIFY
scripts/config.pl unset MBEDTLS_SSL_DTLS_ANTI_REPLAY
scripts/config.pl unset MBEDTLS_SSL_DTLS_BADMAC_LIMIT
scripts/config.pl unset MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
build "TLS-only"
git checkout -- include/mbedtls/config.h
```
The output of the script is as follows:
```
both
text data bss dec hex filename
1820 0 4 1824 720 debug.o (ex library/libmbedtls.a)
0 0 0 0 0 net_sockets.o (ex library/libmbedtls.a)
548 0 0 548 224 ssl_cache.o (ex library/libmbedtls.a)
11155 0 596 11751 2de7 ssl_ciphersuites.o (ex library/libmbedtls.a)
17160 0 0 17160 4308 ssl_cli.o (ex library/libmbedtls.a)
460 0 0 460 1cc ssl_cookie.o (ex library/libmbedtls.a)
17637 0 0 17637 44e5 ssl_srv.o (ex library/libmbedtls.a)
800 0 0 800 320 ssl_ticket.o (ex library/libmbedtls.a)
39322 60 0 39382 99d6 ssl_tls.o (ex library/libmbedtls.a)
88902 60 600 89562 15dda (TOTALS)
DTLS-only
text data bss dec hex filename
1820 0 4 1824 720 debug.o (ex library/libmbedtls.a)
0 0 0 0 0 net_sockets.o (ex library/libmbedtls.a)
548 0 0 548 224 ssl_cache.o (ex library/libmbedtls.a)
11155 0 596 11751 2de7 ssl_ciphersuites.o (ex library/libmbedtls.a)
17072 0 0 17072 42b0 ssl_cli.o (ex library/libmbedtls.a)
460 0 0 460 1cc ssl_cookie.o (ex library/libmbedtls.a)
17565 0 0 17565 449d ssl_srv.o (ex library/libmbedtls.a)
800 0 0 800 320 ssl_ticket.o (ex library/libmbedtls.a)
38953 60 0 39013 9865 ssl_tls.o (ex library/libmbedtls.a)
88373 60 600 89033 15bc9 (TOTALS)
TLS-only
text data bss dec hex filename
1820 0 4 1824 720 debug.o (ex library/libmbedtls.a)
0 0 0 0 0 net_sockets.o (ex library/libmbedtls.a)
548 0 0 548 224 ssl_cache.o (ex library/libmbedtls.a)
11155 0 596 11751 2de7 ssl_ciphersuites.o (ex library/libmbedtls.a)
14916 0 0 14916 3a44 ssl_cli.o (ex library/libmbedtls.a)
460 0 0 460 1cc ssl_cookie.o (ex library/libmbedtls.a)
15852 0 0 15852 3dec ssl_srv.o (ex library/libmbedtls.a)
800 0 0 800 320 ssl_ticket.o (ex library/libmbedtls.a)
27623 60 0 27683 6c23 ssl_tls.o (ex library/libmbedtls.a)
73174 60 600 73834 1206a (TOTALS)
```
It can be seen that a DTLS-only build is now starting to be a bit smaller than
a dual-mode build, which is the purpose of the new build option.
For now the option has no effect.
Adapted existing example config files. The fact that I needed to do this
highlights that this is a slightly incompatible change: existing users need to
update their existing custom configs (if standalone as opposed to based on the
default config) in order to still get the same behaviour.
The alternative would be to have a negative config option (eg NO_TLS or
DTLS_ONLY) but this doesn't fit as nicely with the existing options, so
hopefully the minor incompatibility is acceptable.
I don't think it's worth adding a new component to all.sh:
- builds with both DTLS and TLS are done in the default (and full) config
- TLS-only builds are done with eg config-suite-b.h in test-ref-configs
- a DTLS-only build is done with config-thread.h in test-ref-configs
- builds with none of them (and SSL_TLS_C enabled) are forbidden
When testing a configuration where no ciphersuites have MAC, via
component_test_when_no_ciphersuites_have_mac(), perform a targeted test
of only encrypt-then-MAC tests within ssl-opt.sh.
Context: During a handshake, the SSL/TLS handshake logic constructs
an instance of ::mbedtls_ssl_session representing the SSL session
being established. This structure contains information such as the
session's master secret, the peer certificate, or the session ticket
issues by the server (if applicable).
During a renegotiation, the new session is constructed aside the existing
one and destroys and replaces the latter only when the renegotiation is
complete. While conceptually clear, this means that during the renegotiation,
large pieces of information such as the peer's CRT or the session ticket
exist twice in memory, even though the original versions are removed
eventually.
This commit removes the simultaneous presence of two peer CRT chains
in memory during renegotiation, in the following way:
- Unlike in the case of SessionTickets handled in the previous commit,
we cannot simply free the peer's CRT chain from the previous handshake
before parsing the new one, as we need to verify that the peer's end-CRT
hasn't changed to mitigate the 'Triple Handshake Attack'.
- Instead, we perform a binary comparison of the original peer end-CRT
with the one presented during renegotiation, and if it succeeds, we
avoid re-parsing CRT by moving the corresponding CRT pointer from the
old to the new session structure.
- The remaining CRTs in the peer's chain are not affected by the triple
handshake attack protection, and for them we may employ the canonical
approach of freeing them before parsing the remainder of the new chain.
Note that this commit intends to not change any observable behavior
of the stack. In particular:
- The peer's CRT chain is still verified during renegotiation.
- The tail of the peer's CRT chain may change during renegotiation.
Context: During a handshake, the SSL/TLS handshake logic constructs
an instance of ::mbedtls_ssl_session representing the SSL session
being established. This structure contains information such as the
session's master secret, the peer certificate, or the session ticket
issues by the server (if applicable).
During a renegotiation, the new session is constructed aside the existing
one and destroys and replaces the latter only when the renegotiation is
complete. While conceptually clear, this means that during the renegotiation,
large pieces of information such as the peer's CRT or the session ticket
exist twice in memory, even though the original versions are removed
eventually.
This commit starts removing this memory inefficiency by freeing the old
session's SessionTicket before the one for the new session is allocated.
When MBEDTLS_SSL_ENCRYPT_THEN_MAC is enabled, but not
MBEDTLS_SSL_SOME_MODES_USE_MAC, mbedtls_ssl_derive_keys() and
build_transforms() will attempt to use a non-existent `encrypt_then_mac`
field in the ssl_transform.
Compile [ 93.7%]: ssl_tls.c
[Error] ssl_tls.c@865,14: 'mbedtls_ssl_transform {aka struct mbedtls_ssl_transform}' ha
s no member named 'encrypt_then_mac'
[ERROR] ./mbed-os/features/mbedtls/src/ssl_tls.c: In function 'mbedtls_ssl_derive_keys'
:
./mbed-os/features/mbedtls/src/ssl_tls.c:865:14: error: 'mbedtls_ssl_transform {aka str
uct mbedtls_ssl_transform}' has no member named 'encrypt_then_mac'
transform->encrypt_then_mac = session->encrypt_then_mac;
^~
Change mbedtls_ssl_derive_keys() and build_transforms() to only access
`encrypt_then_mac` if `encrypt_then_mac` is actually present. Fix any
unused variable warnings along the way, by additionally wrapping
function parameters with MBEDTLS_SSL_SOME_MODES_USE_MAC.
Add a regression test to detect when we have regressions with
configurations that do not include any MAC ciphersuites.
Fixes 92231325a7 ("Reduce size of `ssl_transform` if no MAC ciphersuite is enabled")
The existing test `x509parse_crt()` for X.509 CRT parsing
so far used the generic parsing API `mbedtls_x509_crt_parse()`
capable of parsing both PEM encoded and DER encoded certficates,
but was actually only used with DER encoded input data. Moreover,
as the purpose of the test is the testing of the core DER X.509 parsing
functionality, not the PEM vs. DER dispatch (which is now already tested
in the various `x509_crt_info()` tests), the call can be replaced with a
direct call to `mbedtls_x509_parse_crt_der()`.
This commit does that, and further adds to the test an analogous
call to the new API `mbedtls_x509_parse_crt_der_nocopy()` to test
copyless parsing of X.509 certificates.
Context:
The existing API `mbedtls_x509_parse_crt_der()` for parsing DER
encoded X.509 CRTs unconditionally makes creates a copy of the
input buffer in RAM. While this comes at the benefit of easy use,
-- specifically: allowing the user to free or re-use the input
buffer right after the call -- it creates a significant memory
overhead, as the CRT is duplicated in memory (at least temporarily).
This might not be tolerable a resource constrained device.
As a remedy, this commit adds a new X.509 API call
`mbedtls_x509_parse_crt_der_nocopy()`
which has the same signature as `mbedtls_x509_parse_crt_der()`
and almost the same semantics, with one difference: The input
buffer must persist and be unmodified for the lifetime of the
established instance of `mbedtls_x509_crt`, that is, until
`mbedtls_x509_crt_free()` is called.
To prevent dropping the same message over and over again, the UDP proxy
test application programs/test/udp_proxy _logically_ maintains a mapping
from records to the number of times the record has already been dropped,
and stops dropping once a configurable threshold (currently 2) is passed.
However, the actual implementation deviates from this logical view
in two crucial respects:
- To keep the implementation simple and independent of
implementations of suitable map interfaces, it only counts how
many times a record of a given _size_ has been dropped, and
stops dropping further records of that size once the configurable
threshold is passed. Of course, this is not fail-proof, but a
good enough approximation for the proxy, and it allows to use
an inefficient but simple array for the required map.
- The implementation mixes datagram lengths and record lengths:
When deciding whether it is allowed to drop a datagram, it
uses the total datagram size as a lookup index into the map
counting the number of times a package has been dropped. However,
when updating this map, the UDP proxy traverses the datagram
record by record, and updates the mapping at the level of record
lengths.
Apart from this inconsistency, the introduction of the Connection ID
feature leads to yet another problem: The CID length is not part of
the record header but dynamically negotiated during (potentially
encrypted!) handshakes, and it is hence impossible for a passive traffic
analyzer (in this case our UDP proxy) to reliably parse record headers;
especially, it isn't possible to reliably infer the length of a record,
nor to dissect a datagram into records.
The previous implementation of the UDP proxy was not CID-aware and
assumed that the record length would always reside at offsets 11, 12
in the DTLS record header, which would allow it to iterate through
the datagram record by record. As mentioned, this is no longer possible
for CID-based records, and the current implementation can run into
a buffer overflow in this case (because it doesn't validate that
the record length is not larger than what remains in the datagram).
This commit removes the inconsistency in datagram vs. record length
and resolves the buffer overflow issue by not attempting any dissection
of datagrams into records, and instead only counting how often _datagrams_
of a particular size have been dropped.
There is only one practical situation where this makes a difference:
If datagram packing is used by default but disabled on retransmission
(which OpenSSL has been seen to do), it can happen that we drop a
datagram in its initial transmission, then also drop some of its records
when they retransmitted one-by-one afterwards, yet still keeping the
drop-counter at 1 instead of 2. However, even in this situation, we'll
correctly count the number of droppings from that point on and eventually
stop dropping, because the peer will not fall back to using packing
and hence use stable record lengths.
* mbedtls-2.16:
test: Always use `make clean` by itself
list-symbols.sh: if the build fails, print the build transcript
Document "check-names.sh -v"
all.sh: invoke check-names.sh in print-trace-on-exit mode
Print a command trace if the check-names.sh exits unexpectedly
Only use submodule if present
Update change log
Reword ssl_conf_max_frag_len documentation for clarity
Ignore more generated files: seedfile, apidoc
Improve .gitignore grouping and documentation
Generate tags for Vi, for Emacs and with Global
This commit introduces a new SSL error code
`MBEDTLS_ERR_SSL_VERSION_MISMATCH`
which can be used to indicate operation failure due to a
mismatch of version or configuration.
It is put to use in the implementation of `mbedtls_ssl_session_load()`
to signal the attempt to de-serialize a session which has been serialized
in a build of Mbed TLS using a different version or configuration.
This commit improves the test exercising the behaviour of
session deserialization when facing an unexpected version
or config, by testing ver/cfg corruption at any bit in the
ver/cfg header of the serialized data; previously, it had
only tested the first bit of each byte.
This commit makes use of the added space in the session header to
encode the state of those parts of the compile-time configuration
which influence the structure of the serialized session in the
present version of Mbed TLS. Specifically, these are
- the options which influence the presence/omission of fields
from mbedtls_ssl_session (which is currently shallow-copied
into the serialized session)
- the setting of MBEDTLS_X509_CRT_PARSE_C, which determines whether
the serialized session contains a CRT-length + CRT-value pair after
the shallow-copied mbedtls_ssl_session instance.
- the setting of MBEDTLS_SSL_SESSION_TICKETS, which determines whether
the serialized session contains a session ticket.
This commit adds space for two bytes in the header of serizlied
SSL sessions which can be used to determine the structure of the
remaining serialized session in the respective version of Mbed TLS.
Specifically, if parts of the session depend on whether specific
compile-time options are set or not, the setting of these options
can be encoded in the added space.
This commit doesn't yet make use of the fields.
The format of serialized SSL sessions depends on the version and the
configuration of Mbed TLS; attempts to restore sessions established
in different versions and/or configurations lead to undefined behaviour.
This commit adds an 3-byte version header to the serialized session
generated and cleanly fails ticket parsing in case a session from a
non-matching version of Mbed TLS is presented.
The size of the ticket used in this test dropped from 192 to 143 bytes, so
move all sizes used in this test down 50 bytes. Also, we now need to adapt the
server response size as the default size would otherwise collide with the new
mtu value.
We have explicit recommendations to use US spelling for technical writing, so
let's apply this to code as well for uniformity. (My fingers tend to prefer UK
spelling, so this needs to be fixed in many places.)
sed -i 's/\([Ss]eriali\)s/\1z/g' **/*.[ch] **/*.function **/*.data ChangeLog
This test works regardless of the serialisation format and embedded pointers
in it, contrary to the load-save test, though it requires more maintenance of
the test code (sync the member list with the struct definition).
This uncovered a bug that led to a double-free (in practice, in general could
be free() on any invalid value): initially the session structure is loaded
with `memcpy()` which copies the previous values of pointers peer_cert and
ticket to heap-allocated buffers (or any other value if the input is
attacker-controlled). Now if we exit before we got a chance to replace those
invalid values with valid ones (for example because the input buffer is too
small, or because the second malloc() failed), then the next call to
session_free() is going to call free() on invalid pointers.
This bug is fixed in this commit by always setting the pointers to NULL right
after they've been read from the serialised state, so that the invalid values
can never be used.
(An alternative would be to NULL-ify them when writing, which was rejected
mostly because we need to do it when reading anyway (as the consequences of
free(invalid) are too severe to take any risk), so doing it when writing as
well is redundant and a waste of code size.)
Also, while thinking about what happens in case of errors, it became apparent
to me that it was bad practice to leave the session structure in an
half-initialised state and rely on the caller to call session_free(), so this
commit also ensures we always clear the structure when loading failed.
This test appeared to be passing for the wrong reason, it's not actually not
appropriate for the current implementation. The serialised data contains
values of pointers to heap-allocated buffers. There is no reason these should
be identical after a load-save pair. They just happened to be identical when I
first ran the test due to the place of session_free() in the test code and the
fact that the libc's malloc() reused the same buffers. The test no longer
passes if other malloc() implementations are used (for example, when compiling
with asan which avoids re-using the buffer, probably for better error
detection).
So, disable this test for now (we can re-enable it when we changed how
sessions are serialised, which will be done in a future PR, hence the name of
the dummy macro in depends_on). In the next commit we're going to add a test
that save-load is the identity instead - which will be more work in testing as
it will require checking each field manually, but at least is reliable.
This initial test ensures that a load-save function is the identity. It is so
far incomplete in that it only tests sessions without tickets or certificate.
This will be improved in the next commits.
This allows callers to discover what an appropriate size is. Otherwise they'd
have to either try repeatedly, or allocate an overly large buffer (or some
combination of those).
Adapt documentation an example usage in ssl_client2.
Avoid useless copy with mbedtls_ssl_get_session() before serialising.
Used in ssl_client2 for testing and demonstrating usage, but unfortunately
that means mbedtls_ssl_get_session() is no longer tested, which will be fixed
in the next commit.
This provides basic testing for the session (de)serialisation functions, as
well as an example of how to use them.
Tested locally with tests/ssl-opt.sh -f '^Session resume'.
On client side, this is required for the main use case where of serialising a
session for later resumption, in case tickets are used.
On server side, this doesn't change much as ticket_len will always be 0.
This unblocks testing the functions by using them in ssl_client2, which will
be done in the next commit.
This finishes making these functions public. Next step is to get them tested,
but there's currently a blocker for that, see next commit (and the commit
after it for tests).
The next commit with make the implementation publicly available as well.
For now the API is kept unchanged. The save function API has a serious drawback in that the user
must guess what an appropriate buffer size is.
Internally so far this didn't matter because we were only using that API for
ticket creation, and tickets are written to the SSL output buffer whose size
is fixed anyway, but for external users this might not be suitable. Improving
that is left for later.
Also, so far the functions are defined unconditionally. Whether we want to
re-use existing flags or introduce a new one is left for later.
Finally, currently suggested usage of calling get_session() then
session_save() is memory-inefficient in that get_session() already makes a
copy. I don't want to recommend accessing `ssl->session` directly as we want
to prohibit direct access to struct member in the future. Providing a clean
and efficient way is also left to a later commit.
This commit adds the command line option 'bad_cid' to the UDP proxy
`./programs/test/udp_proxy`. It takes a non-negative integral value N,
which if not 0 has the effect of duplicating every 1:N CID records
and modifying the CID in the first copy sent.
This is to exercise the stacks documented behaviour on receipt
of unexpected CIDs.
It is important to send the record with the unexpected CID first,
because otherwise the packet would be dropped already during
replay protection (the same holds for the implementation of the
existing 'bad_ad' option).
This commit modifies mbedtls_ssl_get_peer_cid() to also allow passing
NULL pointers in the arguments for the peer's CID value and length, in
case this information is needed.
For example, some users might only be interested in whether the use of
the CID was negotiated, in which case both CID value and length pointers
can be set to NULL. Other users might only be interested in confirming
that the use of CID was negotiated and the peer chose the empty CID,
in which case the CID value pointer only would be set to NULL.
It doesn't make sense to pass a NULL pointer for the CID length but a
non-NULL pointer for the CID value, as the caller has no way of telling
the length of the returned CID - and this case is therefore forbidden.
This commit modifies the CID configuration API mbedtls_ssl_conf_cid_len()
to allow the configuration of the stack's behaviour when receiving an
encrypted DTLS record with unexpected CID.
Currently, the stack silently ignores DTLS frames with an unexpected CID.
However, in a system which performs CID-based demultiplexing before passing
datagrams to the Mbed TLS stack, unexpected CIDs are a sign of something not
working properly, and users might want to know about it.
This commit introduces an SSL error code MBEDTLS_ERR_SSL_UNEXPECTED_CID
which the stack can return in response to an unexpected CID. It will
conditionally be put to use in subsequent commits.
There are two options:
1. Don't set it, and don't use it during record protection,
guarding the respective paths by a check whether TLS or
DTLS is used.
2. Set it to the default value even for TLS, and avoid the
protocol-dependent branch during record protection.
This commit picks option 2.
ApplicationData records are not protected against loss by DTLS
and our test applications ssl_client2 and ssl_server2 don't
implement any retransmission scheme to deal with loss of the
data they exchange. Therefore, the UDP proxy programs/test/udp_proxy
does not drop ApplicationData records.
With the introduction of the Connection ID, encrypted ApplicationData
records cannot be recognized as such by inspecting the record content
type, as the latter is always set to the CID specific content type for
protected records using CIDs, while the actual content type is hidden
in the plaintext.
To keep tests working, this commit adds CID records to the list of
content types which are protected against dropping by the UDP proxy.
This commit changes the stack's behaviour when facing a record
with a non-matching CID. Previously, the stack failed in this
case, while now we silently skip over the current record.
Previously, ssl_get_next_record() would fetch 13 Bytes for the
record header and hand over to ssl_parse_record_header() to parse
and validate these. With the introduction of CID-based records, the
record length is not known in advance, and parsing and validating
must happen at the same time. ssl_parse_record_header() is therefore
rewritten in the following way:
1. Fetch and validate record content type and version.
2. If the record content type indicates a record including a CID,
adjust the record header pointers accordingly; here, we use the
statically configured length of incoming CIDs, avoiding any
elaborate CID parsing mechanism or dependency on the record
epoch, as explained in the previous commit.
3. Fetch the rest of the record header (note: this doesn't actually
fetch anything, but makes sure that the datagram fetched in the
earlier call to ssl_fetch_input() contains enough data).
4. Parse and validate the rest of the record header as before.
This commit modifies the code surrounding the invocations of
ssl_decrypt_buf() and ssl_encrypt_buf() to deal with a change
of record content type during CID-based record encryption/decryption.
mbedtls_ssl_context contains pointers in_buf, in_hdr, in_len, ...
which point to various parts of the header of an incoming TLS or
DTLS record; similarly, there are pointers out_buf, ... for
outgoing records.
This commit adds fields in_cid and out_cid which point to where
the CID of incoming/outgoing records should reside, if present,
namely prior to where the record length resides.
Quoting https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-04:
The DTLSInnerPlaintext value is then encrypted and the CID added to
produce the final DTLSCiphertext.
struct {
ContentType special_type = tls12_cid; /* 25 */
ProtocolVersion version;
uint16 epoch;
uint48 sequence_number;
opaque cid[cid_length]; // New field
uint16 length;
opaque enc_content[DTLSCiphertext.length];
} DTLSCiphertext;
For outgoing records, out_cid is set in ssl_update_out_pointers()
based on the settings in the current outgoing transform.
For incoming records, ssl_update_in_pointers() sets in_cid as if no
CID was present, and it is the responsibility of ssl_parse_record_header()
to update the field (as well as in_len, in_msg and in_iv) when parsing
records that do contain a CID. This will be done in a subsequent commit.
Finally, the code around the invocations of ssl_decrypt_buf()
and ssl_encrypt_buf() is adapted to transfer the CID from the
input/output buffer to the CID field in the internal record
structure (which is what ssl_{encrypt/decrypt}_buf() uses).
Note that mbedtls_ssl_in_hdr_len() doesn't need change because
it infers the header length as in_iv - in_hdr, which will account
for the CID for records using such.
Using the Connection ID extension increases the maximum record expansion
because
- the real record content type is added to the plaintext
- the plaintext may be padded with an arbitrary number of
zero bytes, in order to prevent leakage of information
through package length analysis. Currently, we always
pad the plaintext in a minimal way so that its length
is a multiple of 16 Bytes.
This commit adapts the various parts of the library to account
for that additional source of record expansion.
Context:
The CID draft does not require that the length of CIDs used for incoming
records must not change in the course of a connection. Since the record
header does not contain a length field for the CID, this means that if
CIDs of varying lengths are used, the CID length must be inferred from
other aspects of the record header (such as the epoch) and/or by means
outside of the protocol, e.g. by coding its length in the CID itself.
Inferring the CID length from the record's epoch is theoretically possible
in DTLS 1.2, but it requires the information about the epoch to be present
even if the epoch is no longer used: That's because one should silently drop
records from old epochs, but not the entire datagrams to which they belong
(there might be entire flights in a single datagram, including a change of
epoch); however, in order to do so, one needs to parse the record's content
length, the position of which is only known once the CID length for the epoch
is known. In conclusion, it puts a significant burden on the implementation
to infer the CID length from the record epoch, which moreover mangles record
processing with the high-level logic of the protocol (determining which epochs
are in use in which flights, when they are changed, etc. -- this would normally
determine when we drop epochs).
Moreover, with DTLS 1.3, CIDs are no longer uniquely associated to epochs,
but every epoch may use a set of CIDs of varying lengths -- in that case,
it's even theoretically impossible to do record header parsing based on
the epoch configuration only.
We must therefore seek a way for standalone record header parsing, which
means that we must either (a) fix the CID lengths for incoming records,
or (b) allow the application-code to configure a callback to implement
an application-specific CID parsing which would somehow infer the length
of the CID from the CID itself.
Supporting multiple lengths for incoming CIDs significantly increases
complexity while, on the other hand, the restriction to a fixed CID length
for incoming CIDs (which the application controls - in contrast to the
lengths of the CIDs used when writing messages to the peer) doesn't
appear to severely limit the usefulness of the CID extension.
Therefore, the initial implementation of the CID feature will require
a fixed length for incoming CIDs, which is what this commit enforces,
in the following way:
In order to avoid a change of API in case support for variable lengths
CIDs shall be added at some point, we keep mbedtls_ssl_set_cid(), which
includes a CID length parameter, but add a new API mbedtls_ssl_conf_cid_len()
which applies to an SSL configuration, and which fixes the CID length that
any call to mbetls_ssl_set_cid() which applies to an SSL context that is bound
to the given SSL configuration must use.
While this creates a slight redundancy of parameters, it allows to
potentially add an API like mbedtls_ssl_conf_cid_len_cb() later which
could allow users to register a callback which dynamically infers the
length of a CID at record header parsing time, without changing the
rest of the API.
The function mbedtls_ssl_hdr_len() returns the length of the record
header (so far: always 13 Bytes for DTLS, and always 5 Bytes for TLS).
With the introduction of the CID extension, the lengths of record
headers depends on whether the records are incoming or outgoing,
and also on the current transform.
Preparing for this, this commit splits mbedtls_ssl_hdr_len() in two
-- so far unmodified -- functions mbedtls_ssl_in_hdr_len() and
mbedtls_ssl_out_hdr_len() and replaces the uses of mbedtls_ssl_hdr_len()
according to whether they are about incoming or outgoing records.
There is no need to change the signature of mbedtls_ssl_{in/out}_hdr_len()
in preparation for its dependency on the currently active transform,
since the SSL context is passed as an argument, and the currently
active transform is referenced from that.
With the introduction of the CID feature, the stack needs to be able
to handle a change of record content type during record protection,
which in particular means that the record content type check will
need to move or be duplicated.
This commit introduces a tiny static helper function which checks
the validity of record content types, which hopefully makes it
easier to subsequently move or duplicate this check.
With the introduction of the CID extension, the record content type
may change during decryption; we must therefore re-consider every
record content type check that happens before decryption, and either
move or duplicate it to ensure it also applies to records whose
real content type is only revealed during decryption.
This commit does this for the silent dropping of unexpected
ApplicationData records in DTLS. Previously, this was caught
in ssl_parse_record_header(), returning
MBEDTLS_ERR_SSL_UNEXPECTED_RECORD which in ssl_get_next_record()
would lead to silent skipping of the record.
When using CID, this check wouldn't trigger e.g. when delayed
encrypted ApplicationData records come on a CID-based connection
during a renegotiation.
This commit moves the check to mbedtls_ssl_handle_message_type()
and returns MBEDTLS_ERR_SSL_NON_FATAL if it triggers, which leads
so silent skipover in the caller mbedtls_ssl_read_record().
The SSL context structure mbedtls_ssl_context contains several pointers
ssl->in_hdr, ssl->in_len, ssl->in_iv, ssl->in_msg pointing to various
parts of the record header in an incoming record, and they are setup
in the static function ssl_update_in_pointers() based on the _expected_
transform for the next incoming record.
In particular, the pointer ssl->in_msg is set to where the record plaintext
should reside after record decryption, and an assertion double-checks this
after each call to ssl_decrypt_buf().
This commit removes the dependency of ssl_update_in_pointers() on the
expected incoming transform by setting ssl->in_msg to ssl->in_iv --
the beginning of the record content (potentially including the IV) --
and adjusting ssl->in_msg after calling ssl_decrypt_buf() on a protected
record.
Care has to be taken to not load ssl->in_msg before calling
mbedtls_ssl_read_record(), then, which was previously the
case in ssl_parse_server_hello(); the commit fixes that.
If a record exhibits an invalid feature only after successful
authenticated decryption, this is a protocol violation by the
peer and should hence lead to connection failure. The previous
code, however, would silently ignore such records. This commit
fixes this.
So far, the only case to which this applies is the non-acceptance
of empty non-AD records in TLS 1.2. With the present commit, such
records lead to connection failure, while previously, they were
silently ignored.
With the introduction of the Connection ID extension (or TLS 1.3),
this will also apply to records whose real content type -- which
is only revealed during authenticated decryption -- is invalid.
In contrast to other aspects of the Connection ID extension,
the CID-based additional data for MAC computations differs from
the non-CID case even if the CID length is 0, because it
includes the CID length.
Quoting the CID draft 04:
- Block Ciphers:
MAC(MAC_write_key, seq_num +
tls12_cid + // New input
DTLSPlaintext.version +
cid + // New input
cid_length + // New input
length_of_DTLSInnerPlaintext + // New input
DTLSInnerPlaintext.content + // New input
DTLSInnerPlaintext.real_type + // New input
DTLSInnerPlaintext.zeros // New input
)
And similar for AEAD and Encrypt-then-MAC.
While 'session hash' is currently unique, so suitable to prove that the
intended code path has been taken, it's a generic enough phrase that in the
future we might add other debug messages containing it in completely unrelated
code paths. In order to future-proof the accuracy of the test, let's use a
more specific string.
The previous comment used "TLS" as a shortcut for "TLS 1.0/1.1" which was
confusing. This partially reflected the names of the calc_verify/finished that
go ssl, tls (for 1.0/1.1) tls_shaxxx (for 1.2), but still it's clearer to be
explicit in the comment - and perhaps in the long term the function names
could be clarified instead.
This commit temporarily comments the copying of the negotiated CIDs
into the established ::mbedtls_ssl_transform in mbedtls_ssl_derive_keys()
until the CID feature has been fully implemented.
While mbedtls_ssl_decrypt_buf() and mbedtls_ssl_encrypt_buf() do
support CID-based record protection by now and can be unit tested,
the following two changes in the rest of the stack are still missing
before CID-based record protection can be integrated:
- Parsing of CIDs in incoming records.
- Allowing the new CID record content type for incoming records.
- Dealing with a change of record content type during record
decryption.
Further, since mbedtls_ssl_get_peer_cid() judges the use of CIDs by
the CID fields in the currently transforms, this change also requires
temporarily disabling some grepping for ssl_client2 / ssl_server2
debug output in ssl-opt.sh.
Part of the record encryption/decryption tests is to gradually
increase the space available at the front and/or at the back of
a record and observe when encryption starts to succeed. If exactly
one of the two parameters is varied at a time, the expectation is
that encryption will continue to succeed once it has started
succeeding (that's not true if both pre- and post-space are varied
at the same time).
Moreover, previously the test would take turns when choosing which
transform should be used for encryption, and which for decryption.
With the introduction of the CID feaature, this switching of transforms
doesn't align with the expectation of eventual success of the encryption,
since the overhead of encryption might be different for the parties,
because both parties may use different CIDs for their outgoing records.
This commit modifies the tests to not take turns between transforms,
but to always use the same transforms for encryption and decryption
during a single round of the test.
This commit modifies ssl_decrypt_buf() and ssl_encrypt_buf()
to include the CID into authentication data during record
protection.
It does not yet implement the new DTLSInnerPlaintext format
from https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-04
This commit adds a static array `cid` to the internal structure
`mbedtls_record` representing encrypted and decrypted TLS records.
The expected evolution of state of this field is as follows:
- When handling an incoming record, the caller of `mbedtls_decrypt_buf()`
has to make sure the CID array field in `mbedtls_record` has been
properly set. Concretely, it will be copied from the CID from the record
header during record parsing.
- During decryption in `mbedtls_decrypt_buf()`, the transforms
incoming CID is compared to the CID in the `mbedtls_record`
structure representing the record to be decrypted.
- For an outgoing TLS record, the caller of `mbedtls_encrypt_buf()`
clears the CID in the `mbedtls_record` structure.
- During encryption in `mbedtls_encrypt_buf()`, the CID field in
`mbedtls_record` will be copied from the out-CID in the transform.
These will be copied from the CID fields in mbedtls_ssl_handshake_params
(outgoing CID) and mbedtls_ssl_context (incoming CID) when the transformation
is set up at the end of the handshake.
* mbedtls_ssl_context gets fields indicating whether the CID extension
should be negotiated in the next handshake, and, if yes, which CID
the user wishes the peer to use.
This information does not belong to mbedtls_ssl_handshake_params
because (a) it is configured prior to the handshake, and (b) it
applies to all subsequent handshakes.
* mbedtls_ssl_handshake_params gets fields indicating the state of CID
negotiation during the handshake. Specifically, it indicates if the
use of the CID extension has been negotiated, and if so, which CID
the peer wishes us to use for outgoing messages.
When using this function to deserialize, it's not a problem to have a session
structure as input as we'll have one around anyway (most probably freshly
deserialised).
However for tests it's convenient to be able to build a transform without
having a session structure around.
Also, removing this structure from parameters makes the function signature
more uniform, the only exception left being the ssl param at the end that's
hard to avoid for now.
We called in tinycrypt in the file names, but uecc in config.h, all.sh and
other places, which could be confusing. Just use tinycrypt everywhere because
that's the name of the project and repo where we took the files.
The changes were made using the following commands (with GNU sed and zsh):
sed -i 's/uecc/tinycrypt/g' **/*.[ch] tests/scripts/all.sh
sed -i 's/MBEDTLS_USE_UECC/MBEDTLS_USE_TINYCRYPT/g' **/*.[ch] tests/scripts/all.sh scripts/config.pl
Configs with no DEBUG_C are use for example in test-ref-configs.pl, which also
runs parts of compat.sh or ssl-opt.sh on them, so the added 'ssl = NULL'
statements will be exercised in those tests at least.
Make it more explicit what's used. Unfortunately, we still need ssl as a
parameter for debugging, and because calc_verify wants it as a parameter (for
all TLS versions except SSL3 it would actually only need handshake, but SSL3
also accesses session_negotiate).
It's also because of calc_verify that we can't make it const yet, but see next
commit.
This commit adds tests to check the behavior of the record encryption
routine `ssl_encrypt_buf` when the buffer surrounding the plaintext is
too small to hold the expansion in the beginning and end (due to IV's,
padding, and MAC).
Each test starts successively increases the space available at the
beginning, end, or both, of the record buffer, and checks that the
record encryption either fails with a BUFFER_TOO_SMALL error, or
that it succeeds. Moreover, if it succeeds, it is checked that
decryption succeeds, too, and results in the original record.
This commit adds tests exercising mutually inverse pairs of
record encryption and decryption transformations for the various
transformation types allowed in TLS: Stream, CBC, and AEAD.
The hash contexts `ssl_transform->md_ctx_{enc/dec}` are not used if
only AEAD ciphersuites are enabled. This commit removes them from the
`ssl_transform` struct in this case, saving a few bytes.
This commit guards code specific to AEAD, CBC and stream cipher modes
in `ssl_derive_keys` by the respective configuration flags, analogous
to the guards that are already in place in the record decryption and
encryption functions `ssl_decrypt_buf` resp. `ssl_decrypt_buf`.
Analogous to the previous commit, but concerning the record decryption
routine `ssl_decrypt_buf`.
An important change regards the checking of CBC padding:
Prior to this commit, the CBC padding check always read 256 bytes at
the end of the internal record buffer, almost always going past the
boundaries of the record under consideration. In order to stay within
the bounds of the given record, this commit changes this behavior by
always reading the last min(256, plaintext_len) bytes of the record
plaintext buffer and taking into consideration the last `padlen` of
these for the padding check. With this change, the memory access
pattern and runtime of the padding check is entirely determined by
the size of the encrypted record, in particular not giving away
any information on the validity of the padding.
The following depicts the different behaviors:
1) Previous CBC padding check
1.a) Claimed padding length <= plaintext length
+----------------------------------------+----+
| Record plaintext buffer | | PL |
+----------------------------------------+----+
\__ PL __/
+------------------------------------...
| read for padding check ...
+------------------------------------...
|
contents discarded
from here
1.b) Claimed padding length > plaintext length
+----------------------------------------+----+
| Record plaintext buffer | PL |
+----------------------------------------+----+
+-------------------------...
| read for padding check ...
+-------------------------...
|
contents discarded
from here
2) New CBC padding check
+----------------------------------------+----+
| Record plaintext buffer | | PL |
+----------------------------------------+----+
\__ PL __/
+---------------------------------------+
| read for padding check |
+---------------------------------------+
|
contents discarded
until here
The previous version of the record encryption function
`ssl_encrypt_buf` takes the entire SSL context as an argument,
while intuitively, it should only depend on the current security
parameters and the record buffer.
Analyzing the exact dependencies, it turned out that in addition
to the currently active `ssl_transform` instance and the record
information, the encryption function needs access to
- the negotiated protocol version, and
- the status of the encrypt-then-MAC extension.
This commit moves these two fields into `ssl_transform` and
changes the signature of `ssl_encrypt_buf` to only use an instance
of `ssl_transform` and an instance of the new `ssl_record` type.
The `ssl_context` instance is *solely* kept for the debugging macros
which need an SSL context instance.
The benefit of the change is twofold:
1) It avoids the need of the MPS to deal with instances of
`ssl_context`. The MPS should only work with records and
opaque security parameters, which is what the change in
this commit makes progress towards.
2) It significantly eases testing of the encryption function:
independent of any SSL context, the encryption function can
be passed some record buffer to encrypt alongside some arbitrary
choice of parameters, and e.g. be checked to not overflow the
provided memory.
This commit adds a structure `mbedtls_record` whose instances
represent (D)TLS records. This structure will be used in the
subsequent adaptions of the record encryption and decryption
routines `ssl_decrypt_buf` and `ssl_encrypt_buf`, which currently
take the entire SSL context as input, but should only use the
record to be acted on as well as the record transformation to use.
The macro constant `MBEDTLS_SSL_MAC_ADD` defined in `ssl_internal.h`
defines an upper bound for the amount of space needed for the record
authentication tag. Its definition distinguishes between the
presence of an ARC4 or CBC ciphersuite suite, in which case the maximum
size of an enabled SHA digest is used; otherwise, `MBEDTLS_SSL_MAC_ADD`
is set to 16 to accomodate AEAD authentication tags.
This assignment has a flaw in the situation where confidentiality is
not needed and the NULL cipher is in use. In this case, the
authentication tag also uses a SHA digest, but the definition of
`MBEDTLS_SSL_MAC_ADD` doesn't guarantee enough space.
The present commit fixes this by distinguishing between the presence
of *some* ciphersuite using a MAC, including those using a NULL cipher.
For that, the previously internal macro `SSL_SOME_MODES_USE_MAC` from
`ssl_tls.c` is renamed and moved to the public macro
`MBEDTLS_SOME_MODES_USE_MAC` defined in `ssl_internal.h`.
Prior to this commit, the security parameter struct `ssl_transform`
contained a `ciphersuite_info` field pointing to the information
structure for the negotiated ciphersuite. However, the only
information extracted from that structure that was used in the core
encryption and decryption functions `ssl_encrypt_buf`/`ssl_decrypt_buf`
was the authentication tag length in case of an AEAD cipher.
The present commit removes the `ciphersuite_info` field from the
`ssl_transform` structure and adds an explicit `taglen` field
for AEAD authentication tag length.
This is in accordance with the principle that the `ssl_transform`
structure should contain the raw parameters needed for the record
encryption and decryption functions to work, but not the higher-level
information that gave rise to them. For example, the `ssl_transform`
structure implicitly contains the encryption/decryption keys within
their cipher contexts, but it doesn't contain the SSL master or
premaster secrets. Likewise, it contains an explicit `maclen`, while
the status of the 'Truncated HMAC' extension -- which determines the
value of `maclen` when the `ssl_transform` structure is created in
`ssl_derive_keys` -- is not contained in `ssl_transform`.
The `ciphersuite_info` pointer was used in other places outside
the encryption/decryption functions during the handshake, and for
these functions to work, this commit adds a `ciphersuite_info` pointer
field to the handshake-local `ssl_handshake_params` structure.
The `ssl_transform` security parameter structure contains opaque
cipher contexts for use by the record encryption/decryption functions
`ssl_decrypt_buf`/`ssl_encrypt_buf`, while the underlying key material
is configured once in `ssl_derive_keys` and is not explicitly dealt with
anymore afterwards. In particular, the key length is not needed
explicitly by the encryption/decryption functions but is nonetheless
stored in an explicit yet superfluous `keylen` field in `ssl_transform`.
This commit removes this field.
* public/mbedtls-2.16: (40 commits)
Clarify comment mangled by an earlier refactoring
Add an "out-of-box" component
Run ssl-opt.sh on 32-bit runtime
Fix typo in data_file generator code
Give credit to OSS-Fuzz for #2404
Remove ssl_cert_test sample app
Fix the proxy seed in Travis runs
Update library version to 2.16.1
Fix errors in AEAD test function
x509.c: Fix potential memory leak in X.509 self test
Remove Circle CI script
Fix ChangeLog entry ordering
Fix typo
Add non-regression test for buffer overflow
Improve documentation of mbedtls_mpi_write_string()
Adapt ChangeLog
Fix 1-byte buffer overflow in mbedtls_mpi_write_string()
Change Perl to Python in test builds
Fix default port number information
Silence pylint
...
requires_config_enabled doesn't support multiple config options.
Tests having multiple configuration dependencies must be prefixed
with multiple invocations of requires_config_enabled instead.
So far, `baremetal.sh --ram --stack` ran `callgrind` to extract
a call stack in an example run of ssl_client2 and ssl_server2.
This, however, needs to be complemented with per-function stack
usage to be able to extract the maximum stack usage.
This commit adds `-fstack-usage` to the CFLAGS used when building
the library in `baremetal.sh --ram` runs, which generates *.su
files indicating the stack usage of individual functions.
This commit adds a minimal test configuration `baremetal.h` to the `configs`
folder supporting ECDHE-ECDSA-AES-CCM-8 with Secp256R1 and SHA-256 only.
The configuration lacks some options which are currently needed to
successfully build and run the example applications `ssl_client2`
and `ssl_server2`, such as `MBEDTLS_NET_C`. To still allow testing
a configuration close to `baremetal.h`, the commit also adds
`baremetal_test.h`, containing minimal amendments to `baremetal.h`
that allow building and running `ssl_client2` and `ssl_server2`.
2019-03-19 15:12:29 +00:00
359 changed files with 48951 additions and 13245 deletions
- The submitter has [accepted the online agreement here with a click through](https://developer.mbed.org/contributor_agreement/)
or for companies or those that do not wish to create an mbed account, a slightly different agreement can be found [here](https://www.mbed.com/en/about-mbed/contributor-license-agreements/)
- The PR follows the [mbed TLS coding standards](https://tls.mbed.org/kb/development/mbedtls-coding-standards)
* Pull requests cannot be accepted until the PR follows the [contributing guidelines](../CONTRIBUTING.md). In particular, each commit must have at least one `Signed-off-by:` line from the committer to certify that the contribution is made under the terms of the [Developer Certificate of Origin](../dco.txt).
* This is just a template, so feel free to use/remove the unnecessary things
## Description
A few sentences describing the overall goals of the pull request's commits.
@ -5,11 +5,6 @@ We gratefully accept bug reports and contributions from the community. There are
- As with any open source project, contributions will be reviewed by the project team and community and may need some modifications to be accepted.
- The contribution should not break API or ABI, unless there is a real justification for that. If there is an API change, the contribution, if accepted, will be merged only when there will be a major release.
Contributor License Agreement (CLA)
-----------------------------------
- All contributions, whether large or small, require a Contributor's License Agreement (CLA) to be accepted. This is because source code can possibly fall under copyright law and we need your consent to share in the ownership of the copyright.
- To accept the Contributor’s License Agreement (CLA), individual contributors can do this by creating an Mbed account and [accepting the online agreement here with a click through](https://developer.mbed.org/contributor_agreement/). Alternatively, for contributions from corporations, or those that do not wish to create an Mbed account, a slightly different agreement can be found [here](https://www.mbed.com/en/about-mbed/contributor-license-agreements/). This agreement should be signed and returned to Arm as described in the instructions given.
Coding Standards
----------------
- We would ask that contributions conform to [our coding standards](https://tls.mbed.org/kb/development/mbedtls-coding-standards), and that contributions are fully tested before submission, as mentioned in the [Tests](#tests) and [Continuous Integration](#continuous-integration-tests) sections.
@ -19,12 +14,13 @@ Coding Standards
Making a Contribution
---------------------
1. [Check for open issues](https://github.com/ARMmbed/mbedtls/issues) or [start a discussion](https://tls.mbed.org/discussions) around a feature idea or a bug.
1. [Check for open issues](https://github.com/ARMmbed/mbedtls/issues) or [start a discussion](https://lists.trustedfirmware.org/mailman/listinfo/mbed-tls) around a feature idea or a bug.
1. Fork the [Mbed TLS repository on GitHub](https://github.com/ARMmbed/mbedtls) to start making your changes. As a general rule, you should use the ["development" branch](https://github.com/ARMmbed/mbedtls/tree/development) as a basis.
1. Write a test which shows that the bug was fixed or that the feature works as expected.
1. Send a pull request (PR) and work with us until it gets merged and published. Contributions may need some modifications, so a few rounds of review and fixing may be necessary. We will include your name in the ChangeLog :)
1. For quick merging, the contribution should be short, and concentrated on a single feature or topic. The larger the contribution is, the longer it would take to review it and merge it.
1. Mbed TLS is released under the Apache license, and as such, all the added files should include the Apache license header.
1. All new files should include the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) standard license header where possible.
1. Ensure that each commit has at least one `Signed-off-by:` line from the committer. If anyone else contributes to the commit, they should also add their own `Signed-off-by:` line. By adding this line, contributor(s) certify that the contribution is made under the terms of the [Developer Certificate of Origin](dco.txt). The contribution licensing is described in the [License section of the README](README.md#License).
API/ABI Compatibility
---------------------
@ -46,18 +42,14 @@ Mbed TLS maintains several LTS (Long Term Support) branches, which are maintaine
When backporting to these branches please observe the following rules:
1. Any change to the library which changes the API or ABI cannot be backported.
2. All bug fixes that correct a defect that is also present in an LTS branch must be backported to that LTS branch. If a bug fix introduces a change to the API such as a new function, the fix should be reworked to avoid the API change. API changes without very strong justification are unlikely to be accepted.
3. If a contribution is a new feature or enhancement, no backporting is required. Exceptions to this may be additional test cases or quality improvements such as changes to build or test scripts.
1. Any change to the library which changes the API or ABI cannot be backported.
1. All bug fixes that correct a defect that is also present in an LTS branch must be backported to that LTS branch. If a bug fix introduces a change to the API such as a new function, the fix should be reworked to avoid the API change. API changes without very strong justification are unlikely to be accepted.
1. If a contribution is a new feature or enhancement, no backporting is required. Exceptions to this may be additional test cases or quality improvements such as changes to build or test scripts.
It would be highly appreciated if contributions are backported to LTS branches in addition to the [development branch](https://github.com/ARMmbed/mbedtls/tree/development) by contributors.
Mbed TLS is a C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. Its small code footprint makes it suitable for embedded systems.
Configuration
-------------
@ -167,21 +169,12 @@ Mbed TLS can be ported to many different architectures, OS's and platforms. Befo
- [What external dependencies does Mbed TLS rely on?](https://tls.mbed.org/kb/development/what-external-dependencies-does-mbedtls-rely-on)
- [How do I configure Mbed TLS](https://tls.mbed.org/kb/compiling-and-building/how-do-i-configure-mbedtls)
License
-------
Unless specifically indicated otherwise in a file, Mbed TLS files are provided under the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. See [here](./apache-2.0.txt) for the full text of this license. Contributors must accept that their contributions are made under both the Apache-2.0 AND [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) licenses. This enables LTS (Long Term Support) branches of the software to be provided under either the Apache-2.0 OR GPL-2.0-or-later licenses.
Contributing
------------
We gratefully accept bug reports and contributions from the community. There are some requirements we need to fulfill in order to be able to integrate contributions:
- All contributions, whether large or small require a Contributor's License Agreement (CLA) to be accepted. This is because source code can possibly fall under copyright law and we need your consent to share in the ownership of the copyright.
- We would ask that contributions conform to [our coding standards](https://tls.mbed.org/kb/development/mbedtls-coding-standards), and that contributions should be fully tested before submission.
- As with any open source project, contributions will be reviewed by the project team and community and may need some modifications to be accepted.
To accept the Contributor’s Licence Agreement (CLA), individual contributors can do this by creating an Mbed account and [accepting the online agreement here with a click through](https://os.mbed.com/contributor_agreement/). Alternatively, for contributions from corporations, or those that do not wish to create an Mbed account, a slightly different agreement can be found [here](https://www.mbed.com/en/about-mbed/contributor-license-agreements/). This agreement should be signed and returned to Arm as described in the instructions given.
### Making a Contribution
1. [Check for open issues](https://github.com/ARMmbed/mbedtls/issues) or [start a discussion](https://forums.mbed.com/c/mbed-tls) around a feature idea or a bug.
2. Fork the [Mbed TLS repository on GitHub](https://github.com/ARMmbed/mbedtls) to start making your changes. As a general rule, you should use the "development" branch as a basis.
3. Write a test which shows that the bug was fixed or that the feature works as expected.
4. Send a pull request and bug us until it gets merged and published. Contributions may need some modifications, so work with us to get your change accepted. We will include your name in the ChangeLog :)
We gratefully accept bug reports and contributions from the community. Please see the [contributing guidelines](CONTRIBUTING.md) for details on how to do this.
#error "MBEDTLS_SSL_CONF_MIN_MINOR_VER, MBEDTLS_SSL_CONF_MAX_MINOR_VER, MBEDTLS_SSL_CONF_MIN_MAJOR_VER, MBEDTLS_SSL_CONF_MAX_MAJOR_VER must be defined simultaneously"
#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */
#define MBEDTLS_ERR_PLATFORM_FAULT_DETECTED -0x0071 /**< A hardware fault was detected in a critical path. As a security precaution this should be treated as a potential physical attack */
mbedtls_snprintf(buf,buflen,"PLATFORM - A hardware fault was detected in a critical path. As a security precaution this should be treated as a potential physical attack");