Commit Graph

1056 Commits

Author SHA1 Message Date
Manuel Pégourié-Gonnard
44ba6b0d26 Merge remote-tracking branch 'restricted/pr/594' into baremetal-proposed
* 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
2019-07-03 10:22:28 +02:00
Manuel Pégourié-Gonnard
37261e6f6b Merge remote-tracking branch 'restricted/pr/601' into baremetal-proposed
* 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
  ...
2019-07-03 10:04:13 +02:00
Manuel Pégourié-Gonnard
417d2ce076 Merge remote-tracking branch 'restricted/pr/584' into baremetal-proposed
* 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
  ...
2019-07-03 10:03:45 +02:00
Hanno Becker
c2cfdaa693 Allow config'n of incl of CertificateReq CA list Y/N at compile-time
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 |
2019-07-02 16:42:45 +01:00
Hanno Becker
2d9623f7d5 Allow configuration of endpoint (cli/srv) at compile-time
Introduces MBEDTLS_SSL_CONF_ENDPOINT to allow to choose between
server- or client-builds at compile-time.

Impact on code-size:

|  | GCC 8.2.1 | ARMC5 5.06 | ARMC6 6.12 |
| --- | --- | --- | --- |
| `libmbedtls.a` (client only) before  | 18355 | 18815 | 21485 |
| `libmbedtls.a` (client only) after | 18219 | 18683 | 21347 |
| gain in Bytes (client only) | 136 | 132 | 138 |
| `libmbedtls.a` (server only) before  | 18715 | 18987 | 21883 |
| `libmbedtls.a` (server only) after | 18595 | 18823 | 21717 |
| gain in Bytes (server only) | 120 | 164 | 166 |
2019-07-02 16:42:41 +01:00
Hanno Becker
1f835fa22b Allow configuration of read timeouts at compile-time
Introduces compile-time constants
- MBEDTLS_SSL_CONF_READ_TIMEOUT
- MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN
- MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX
which allow to configure the read timeouts and
minimum/maximum handshake timeout at compile time.

Impact on code-size:

|  | GCC 8.2.1 | ARMC5 5.06 | ARMC6 6.12 |
| --- | --- | --- | --- |
| `libmbedtls.a` before  | 23147 | 23781 | 26703 |
| `libmbedtls.a` after | 23131 | 23753 | 26673 |
| gain in Bytes | 16 | 28 | 30 |
2019-07-02 16:42:10 +01:00
Hanno Becker
e0200dad63 Allow configuration of ConnectionID at compile-time
Introduces
- MBEDTLS_SSL_CONF_CID_LEN and
- MBEDTLS_SSL_CONF_IGNORE_UNEXPECTED_CID
to control
- the length of incoming CIDs
- the behaviour in receipt of unexpected CIDs
at compile-time.

Impact on code-size:

|  | GCC 82.1 | ARMC5 5.06 | ARMC6 6.12 |
| --- | --- | --- | --- |
| `libmbedtls.a` before | 23223 | 23865 | 26775 |
| `libmbedtls.a` after  | 23147 | 23781 | 26703 |
| gain in Bytes | 76 | 84 | 72 |
2019-07-02 16:41:35 +01:00
Hanno Becker
b0b2b67568 Allow compile-time configuration of legacy renegotiation
Introduces MBEDTLS_SSL_CONF_ALLOW_LEGACY_RENEGOTIATION
allowing to configure enforcing secure renegotiation at
compile-time.

Impact on code-size:

|  | GCC | ARMC5 | ARMC6 |
| --- | --- | --- | --- |
| `libmbedtls.a` after  | 23379 | 23929 | 27727 |
| `libmbedtls.a` before | 23307 | 23865 | 27615 |
| gain in Bytes | 72 | 64 | 112 |
2019-07-02 16:41:34 +01:00
Hanno Becker
acd4fc0ac9 Allow compile-time configuration of authentication mode
Introduces MBEDTLS_SSL_CONF_AUTHMODE to fix the authentication
mode (none, optional, mandatory) at compile-time.

Impact on code-size:

|  | GCC | ARMC5 | ARMC6 |
| --- | --- | --- | --- |
| `libmbedtls.a` before | 23487 | 24025 | 27885 |
| `libmbedtls.a` after  | 23379 | 23929 | 27727 |
| gain in Bytes | 108 | 96 | 157 |
2019-07-02 16:41:29 +01:00
Hanno Becker
de67154658 Allow compile-time configuration of DTLS badmac limit
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 |
2019-07-02 16:40:50 +01:00
Manuel Pégourié-Gonnard
7b80c64de4 Fix compile-time guard for optional field in struct 2019-07-02 16:24:55 +02:00
Jarno Lamsa
29f2dd0a7b Address review comments 2019-07-02 15:12:29 +02:00
Jarno Lamsa
59bd12bf14 Add new config MBEDTLS_SSL_SESSION_RESUMPTION
Add a new configuration option MBEDTLS_SSL_SESSION_RESUMPTION
to enable/disable the session resumption feature including
ticket and cache based session resumption.
2019-07-02 15:12:29 +02:00
Jarno Lamsa
7be14065e2 Add config MBEDTLS_SSL_SESSION_CACHE
Add configuration option MBEDTLS_SSL_SESSION_CACHE to control
enabling/disabling of the cache based session resumption.
2019-07-02 15:12:29 +02:00
Hanno Becker
2224ccf390 Don't use assertion for failures of mbedtls_x509_crt_x_acquire()
These functions may afil in a regular run, e.g. due to an out of memory
error.
2019-06-28 14:48:31 +01:00
Hanno Becker
c6d1c3ed1c Remove frame/pk parameter from mbedtls_x509_crt_xxx_release() 2019-06-25 09:07:16 +01:00
Hanno Becker
8c13ee615f Make use of CRT acquire/release in ssl_parse_certificate_verify()
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.
2019-06-25 09:06:26 +01:00
Hanno Becker
7f376f4ece Allow compile-time configuration of DTLS anti replay
Introduce MBEDTLS_SSL_CONF_ANTI_REPLAY to allow configuring
the use/nonuse of DTLS anti replay protection at compile-time.

Impact on code-size, measured with
> ./scripts/baremetal.sh --rom --gcc --armc5 --armc6

|  | GCC | ARMC5 | ARMC6 |
| --- | --- | --- | --- |
| `libmbedtls.a` before | 23559 | 24089 | 27921 |
| `libmbedtls.a` after  | 23511 | 24049 | 27903 |
| gain in Bytes | 48 | 40 | 18 |
2019-06-25 08:43:31 +01:00
Hanno Becker
f765ce617f Remove ExtendedMS configuration API if hardcoded at compile-time
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.
2019-06-25 08:42:20 +01:00
Hanno Becker
a49ec56f51 Introduce getter function for extended_ms field in HS struct 2019-06-25 08:42:20 +01:00
Hanno Becker
aabbb582eb Exemplify harcoding SSL config at compile-time in example of ExtMS
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.
2019-06-25 08:42:20 +01:00
Manuel Pégourié-Gonnard
393338ca78
Merge pull request #586 from ARMmbed/remove_peer_crt_after_handshake_no_digest-baremetal
[Baremetal] Don't store peer CRT digest if renegotiation is disabled
2019-06-24 18:12:00 +02:00
Manuel Pégourié-Gonnard
79cf74a95f
Merge pull request #583 from ARMmbed/remove_peer_crt_after_handshake-baremetal
[Baremetal] Allow removal of peer certificate to reduce RAM usage
2019-06-24 18:11:46 +02:00
Manuel Pégourié-Gonnard
cc3b7ccb04
Merge pull request #579 from Patater/bm-dont-use-non-existent-encrypt-then-mac
[Baremetal] ssl: Don't access non-existent encrypt_then_mac field
2019-06-24 18:06:53 +02:00
Hanno Becker
5882dd0856 Remove CRT digest from SSL session if !RENEGO + !KEEP_PEER_CERT
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).
2019-06-19 16:56:51 +01:00
Hanno Becker
0528f82fa9 Clarify documentation of serialized session format 2019-06-19 14:59:42 +01:00
Hanno Becker
17daaa5cc6 Move return statement in ssl_srv_check_client_no_crt_notification
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.
2019-06-19 14:59:42 +01:00
Hanno Becker
2326d20361 Validate consistency of certificate hash type and length in session 2019-06-19 14:59:42 +01:00
Hanno Becker
fd5dc8ae07 Fix unused variable warning in ssl_parse_certificate_coordinate()
This was triggered in client-only builds.
2019-06-19 14:59:42 +01:00
Hanno Becker
42de8f8a42 Fix typo in documentation of ssl_parse_certificate_chain() 2019-06-19 14:59:41 +01:00
Hanno Becker
9d64b789cf Set peer CRT length only after successful allocation 2019-06-19 10:26:50 +01:00
Hanno Becker
257ef65d94 Remove question in comment about verify flags on cli vs. server 2019-06-19 10:26:50 +01:00
Hanno Becker
34106f6ae2 Free peer CRT chain immediately after verifying it
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.
2019-06-19 10:26:50 +01:00
Hanno Becker
0cc7af5be5 Parse peer's CRT chain in-place from the input buffer 2019-06-19 10:26:50 +01:00
Hanno Becker
17572473c6 Correct compile-time guards for ssl_clear_peer_cert()
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.
2019-06-19 10:26:50 +01:00
Hanno Becker
bfab9dfea1 Guard mbedtls_ssl_get_peer_cert() by new compile-time option 2019-06-19 10:26:17 +01:00
Hanno Becker
81d11aa640 Adapt mbedtls_ssl_parse_certificate() to removal of peer_cert field 2019-06-19 10:25:02 +01:00
Hanno Becker
5062897507 Adapt ssl_clear_peer_cert() to removal of peer_cert field 2019-06-19 10:25:02 +01:00
Hanno Becker
d5258faa29 Adapt mbedtls_ssl_session_copy() to removal of peer_cert field 2019-06-19 10:25:02 +01:00
Hanno Becker
cf291d63dd Make a copy of peer's raw public key after verifying its CRT chain
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.
2019-06-19 10:25:02 +01:00
Hanno Becker
3bf8cdf2f8 Add field for peer's raw public key to TLS handshake param structure
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.
2019-06-19 10:25:01 +01:00
Hanno Becker
2e6d34761f Remove peer CRT from mbedtls_ssl_session if !KEEP_PEER_CERT 2019-06-19 10:25:01 +01:00
Hanno Becker
4a2f8e584f Add peer CRT digest to session tickets
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.
2019-06-19 10:25:01 +01:00
Hanno Becker
e4aeb76a2c Parse and verify peer CRT chain in local variable
`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.
2019-06-19 10:25:01 +01:00
Hanno Becker
df75938b84 Mitigate triple handshake attack by comparing digests only
This paves the way for the removal of the peer CRT chain from
`mbedtls_ssl_session`.
2019-06-19 10:25:01 +01:00
Hanno Becker
3008d2869f Compute digest of peer's end-CRT in mbedtls_ssl_parse_certificate() 2019-06-19 10:25:01 +01:00
Hanno Becker
9fb6e2e203 Extend mbedtls_ssl_session by buffer holding peer CRT digest 2019-06-19 10:25:01 +01:00
Hanno Becker
58fccf2f62 Give ssl_session_copy() external linkage
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.
2019-06-19 10:25:01 +01:00
Hanno Becker
35e41771fe Allow passing any X.509 CRT chain to ssl_parse_certificate_chain()
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`.
2019-06-19 10:25:01 +01:00
Hanno Becker
3cf5061091 Introduce helper function for peer CRT chain verification 2019-06-19 10:25:01 +01:00