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.
* origin/pr/2714:
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()
* origin/pr/2701:
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
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.
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.
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.
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.
Introduce a new configuration option MBEDTLS_CHECK_PARAMS_ASSERT,
which is disabled by default. When this option is enabled,
MBEDTLS_PARAM_FAILED defaults to assert rather than to a call to
mbedtls_param_failed, and <assert.h> is included.
This fixes#2671 (no easy way to make MBEDTLS_PARAM_FAILED assert)
without breaking backward compatibility. With this change,
`config.pl full` runs tests with MBEDTLS_PARAM_FAILED set to assert,
so the tests will fail if a validation check fails, and programs don't
need to provide their own definition of mbedtls_param_failed().
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.