mbedtls_mpi_read_binary() calls memcpy() with the source pointer being
the source pointer passed to mbedtls_mpi_read_binary(), the latter may
be NULL if the buffer length is 0 (and this happens e.g. in the ECJPAKE
test suite). The behavior of memcpy(), in contrast, is undefined when
called with NULL source buffer, even if the length of the copy operation
is 0.
This commit fixes this by explicitly checking that the source pointer is
not NULL before calling memcpy(), and skipping the call otherwise.
Context: The function `mbedtls_mpi_fill_random()` uses a temporary stack
buffer to hold the random data before reading it into the target MPI.
Problem: This is inefficient both computationally and memory-wise.
Memory-wise, it may lead to a stack overflow on constrained devices with
limited stack.
Fix: This commit introduces the following changes to get rid of the
temporary stack buffer entirely:
1. It modifies the call to the PRNG to output the random data directly
into the target MPI's data buffer.
This alone, however, constitutes a change of observable behaviour:
The previous implementation guaranteed to interpret the bytes emitted by
the PRNG in a big-endian fashion, while rerouting the PRNG output into the
target MPI's limb array leads to an interpretation that depends on the
endianness of the host machine.
As a remedy, the following change is applied, too:
2. Reorder the bytes emitted from the PRNG within the target MPI's
data buffer to ensure big-endian semantics.
Luckily, the byte reordering was already implemented as part of
`mbedtls_mpi_read_binary()`, so:
3. Extract bigendian-to-host byte reordering from
`mbedtls_mpi_read_binary()` to a separate internal function
`mpi_bigendian_to_host()` to be used by `mbedtls_mpi_read_binary()`
and `mbedtls_mpi_fill_random()`.
The calls to cipher_finish didn't actually do anything:
- the cipher mode is always ECB
- in that case cipher_finish() only sets *olen to zero, and returns either 0
or an error depending on whether there was pending data
- olen is a local variable in the caller, so setting it to zero right before
returning is not essential
- the return value of cipher_finis() was not checked by the caller so that's
not useful either
- the cipher layer does not have ALT implementations so the behaviour
described above is unconditional on ALT implementations (in particular,
cipher_finish() can't be useful to hardware as (with ECB) it doesn't call any
functions from lower-level modules that could release resources for example)
Since the calls are causing issues with parameter validation, and were no
serving any functional purpose, it's simpler to just remove them.
Somehow, mbedtls_sha256_ret() is defined even if MBEDTLS_SHA256_ALT
is set, and it is using SHA256_VALIDATE_RET. The documentation should
be enhanced to indicate that MBEDTLS_SHA256_ALT does _not_ replace
the entire module, but only the core SHA-256 functions.
Somehow, mbedtls_sha512_ret() is defined even if MBEDTLS_SHA512_ALT
is set, and it is using SHA512_VALIDATE_RET. The documentation should
be enhanced to indicate that MBEDTLS_SHA512_ALT does _not_ replace
the entire module, but only the core SHA-512 functions.
Somehow, mbedtls_sha1_ret() is defined even if MBEDTLS_SHA1_ALT
is set, and it is using SHA1_VALIDATE_RET. The documentation should
be enhanced to indicate that MBEDTLS_SHA1_ALT does _not_ replace
the entire module, but only the core SHA-1 functions.
Document when a context must be initialized or not, when it must be
set up or not, and whether it needs a private key or a public key will
do.
The implementation is sometimes more liberal than the documentation,
accepting a non-set-up context as a context that can't perform the
requested information. This preserves backward compatibility.
The MPI_VALIDATE_RET() macro cannot be used for parameter
validation of mbedtls_mpi_lsb() because this function returns
a size_t.
Use the underlying MBEDTLS_INTERNAL_VALIDATE_RET() insteaed,
returning 0 on failure.
Also, add a test for this behaviour.