-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Driver-only ECC: goals and strategy #6839
Comments
Looks like a plan. One hurdle I'm aware of is calculating buffer sizes, where Another potential hurdle is verifying a signature before entropy is available. As this is a new feature, it can wait until we get around to implementing partial initialization. There is a known gap in PSA that compressed points are not supported in PSA, and can't be without both an API extension and extra requirements on drivers. |
@gilles-peskine-arm @ronald-cron-arm Do you happen to have any insight on this? Note: I'm not suggesting you spend time investigating this, just wanted to check if that rings a bell before I dig further. For reference, here's the component I added, and I'm attaching the output of component_test_psa_crypto_config_accel_ecc () {
msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated ECC"
# Configure and build the test driver library
# --------------------------------------------
# Disable ALG_STREAM_CIPHER and ALG_ECB_NO_PADDING to avoid having
# partial support for cipher operations in the driver test library.
scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
# SHA384 needed for some ECDSA signature tests.
scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA384_C
scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA512_C
# TODO: add EC J-PAKE once driver dispatch is done
loc_accel_list="ALG_ECDH ALG_ECDSA ALG_DETERMINISTIC_ECDSA KEY_TYPE_ECC_KEY_PAIR KEY_TYPE_ECC_PUBLIC_KEY"
loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
make -C tests libtestdriver1.a CFLAGS="$ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
# Restore test driver base configuration
scripts/config.py -f tests/include/test/drivers/config_test_driver.h unset MBEDTLS_SHA384_C
scripts/config.py -f tests/include/test/drivers/config_test_driver.h unset MBEDTLS_SHA512_C
# Configure and build the main libraries
# ---------------------------------------
# start with default + driver support
scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS
scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
# disable modules for which we have drivers
scripts/config.py unset MBEDTLS_ECDSA_C
scripts/config.py unset MBEDTLS_ECDH_C
scripts/config.py unset MBEDTLS_ECJPAKE_C
# dependencies
scripts/config.py unset MBEDTLS_SSL_PROTO_TLS1_3
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
# build and link with test drivers
loc_accel_flags="$loc_accel_flags $( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
make CFLAGS="$ASAN_CFLAGS -O -Werror -I../tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS"
# make sure these were not auto-re-enabled by accident
not grep mbedtls_ecdsa_ library/ecdsa.o
not grep mbedtls_ecdh_ library/ecdh.o
# Run the tests
# -------------
msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated ECC"
make test
} |
No, this looks weird to me. What I'd do next:
|
It's actually quite simple: the cases that fail are exactly those that end up calling #if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
if( PSA_KEY_TYPE_IS_ECC( slot->attr.type ) )
{
// [do it]
} else
#endif
// [handle other types then eventually ]
return( PSA_ERROR_NOT_SUPPORTED ); So, I think the problem is indeed that we are lacking driver support for cooked key derivation: the is no point in the call chain between the public function So, I think our ability to accelerate both ECDH and ECDSA at the same time depends on implementing driver support for cooked key derivation. Also, the part that was most surprising to me and initially made me doubt that it was about this, is that tests using Unless someone beats me to it, I'll raise a PR (if the simple fix just works without uncovering other issues) or create an issue about it tomorrow. |
#6873 - let's see what the CI says |
So, after a first read of of #5451 and looking at subsequent issues, it looks to me that what's required before we can accelerate all ECC algorithms in a single build and have the existing tests for key derivation pass, would be #5489 - including the ability for So, basically the driver-only ECC EPIC has an external dependency on some of the "drivers for KDFs" work. Specifically, the sub-goal TL.PSA (as opposed to just TL-ecdh.PSA + TL-ecdsa.PSA + TL-ecjpake.PSA) depends on #5489 (and perhaps more depending on how we interpret the scope of that issue). |
Deriving an ECC key from a KDF output is a PSA-only functionality that is not used by any higher-level code inside the library. It should not be part of the driver-only ECC epic, because that would block a useful feature with high demand (do TLS or other network protocol with accelerated ECC and save the code size from I think this means that when the driver-only ECC epic is complete, there will be a feature gap: ECC key derivation won't work with accelerated-only ECC until ECC key derivation works with accelerated ECC. |
In the driver specification language, a driver can declare that it supports e.g. ECDH and ECDSA but not key derivation. The Similarly the |
Ah, that was not accurate. What triggers the failures is not when both ECDH and ECDSA (and now ECJPAKE) are accelerated, what triggers the problem is when on top of that we try to accelerate
Agreed. I think this can easily be achieved by declaring that the tests for ECC key derivation depend on |
@gilles-peskine-arm @valeriosetti I've updating the list of restrictions and indicating for each one at which level they apply:
It turns out there are three restrictions that appear when disabling So, now I'm tempted to make Wdyt? |
Note: as @valeriosetti mentions here, a middle ground could be to not document it publicly in |
I'm reluctant to make I'd prefer to introduce feature-specific configuration options (where they don't already exist) and automatically enable
|
@gilles-peskine-arm thanks for your feedback!
|
@gilles-peskine-arm Thanks for your input! One minor point first:
That is actually unrelated to Other than that, I tend to agree. Initially, I wanted Then I noticed we didn't have the proper feature macros for users to express "I want to read compress points" or "I want to derive ECC keys", so I thought instead of adding two public options for that, we could add just one, namely Regarding compressed points, I'm thinking Regarding PSA derivation of ECP keys, what to you think would be an appropriate name / granularity? I was thinking Wdyt? |
About new |
Closing as the work has been completed. |
This issue is used as a place to document the goals of the driver-only ECC EPIC and discuss the general strategy towards those goals.
Broader context: see
docs/architecture/psa-migration/strategy.md
; this is about implementing goal 5 "compile out our implementation when a driver is available" for elliptic-curve cryptography (ECC).Goals
Intermediate definition: "everything works" means that in a configuration with
MBEDTLS_USE_PSA_CRYPTO
enabled, we can build and use crypto, X.509 and TLS, and all the tests pass, with no more tests skipped than morally justified (see "restrictions" below).MBEDTLS_ECDH_C
,MBEDTLS_ECDSA_C
,MBEDTLS_ECJPAKE_C
) can be removed, and everything works. (But this might still requires the curves used to be present on both sides.)ecp_mul()
and associated) fromecp.c
and everything works.Previously: CV (curves): In the situation above, everything works even when some of the curves used are only supported on the PSA side.ecp.c
fully and everything works.MBEDTLS_BIGNUM_C
and everything works.*Note: that is, not included in the build at all, the case where they're provided by accelerators is explicitly out of scope for this EPIC which is only about taking advantage of ECC accelerators to compile things out. If the same is desired for RSA at some point, it will be a separate EPIC.
Restrictions: the following are not expected to work in driver-only builds in the immediate future:
Parsing explicit (non-named) curves: it won't be possible to enableSee PK: study: support SpecifiedECDomain parsing withoutMBEDTLS_PK_PARSE_EC_EXTENDED
at ECPf and beyond.ECP_LIGHT
#7628Testing
We'll have new components in
all.sh
similar tocomponent_test_psa_crypto_config_accel_hash_use_psa()
materializing the completion of each goal. However, it is desirable to minimize the total number of components in the end, so we may merge the components for two successive goals, but only if there is not loss of functionality between them. All components uselibtestdriver1
and have names starting withtest_psa_crypto_config_accel_
. Currently the testing plan looks as follows:accel_ecdsa
,accel_ecdh
,accel_pake
each accelerating only one of the top-level ECC modules. Each running onlymake test
(nossl-opt.sh
and based on default config (noUSE_PSA
, so have to disable TLS key exchanges the depend on the accelerated module) (except PAKE but is that intentional?), with no testing of coverage parity. Testing for all 3 accelerated is merged with the ECPa test below. Testing with only 2 accelerated doesn't seem worth it. (Questions: is testing with only 1 accelerated actually worth it? Is testing withoutUSE_PSA
worth it?)!ECP_C && ECP_LIGHT
(that is,ecp.o
is not empty but does not containmbedtls_ecp_mul
). Starting from full config, runningssl-opt.sh
and with coverage parity. Currently namedaccel_all_ec_algs_use_psa
, might be renamed toaccel_ecc_ecp_light_only
. No loss of functionality compared to TL.!ECP_C && !ECP_LIGHT
(that is,ecp.o
is empty). Starting from full config, runningssl-opt.sh
(eventually) and with coverage parity. Currently namedaccel_all_ec_algs_use_psa
, might be renamed toaccel_ecc_no_ecp_at_all
. (In progress, only crypto including PK so far, X.509 and TLS up next.) Loss of functionality compare to previous component: compressed points, (SpecifiedECDomain until 7628), ECC key derivation.!ECP_C && !ECP_LIGHT && !BIGNUM_C
(that is,ecp.o
andbignum.o
both empty). Starting from full config, runningssl-opt.sh
and with coverage parity. Planned nameaccel_ecc_no_bignum
. Not started yet. Loss of functionality compare to previous component: DHM, RSA, things that depend on it.Testing for coverage parity means there is a companion reference component with the same configuration except nothing's accelerated, and
analyze_outcomes.py
will check that all tests that passed in the reference configuration also do (as opposed to being skipped) in the driver-only configuration.Intermediate goals
We can mainly progress along two axes:
Depth of the modules removed: this is how goals are defined above: first, remove the top-level module (ECDH, ECDSA, ECJPAKE) when accelerators are present, then remove the intermediate ECP, then the lowest-level module, Bignum. The obvious ordering here is top-down.
Breadth of the features working: the goals are stated with "everything works" and there can be any number of stepping stones towards "everything":
USE_PSA_CRYPTO
) - possible intermediate steps for parse / write / crypto operations;Here the natural ordering is generally bottom-up / lateral movement in the upper layers: we need to do PK before X.509 before the TLS key exchanges that use a certificate, which we can then do in any order, but there are exceptions: for example we can do the TLS 1.2 ECJPAKE key exchange before we did X.509 or PK.
Strategy
There are two kinds of problems in defining the strategy:
High-level dependency matrix and possible refinements
It was noted in "Intermediate goals" above that there are two axes. This can be visualized as a matrix of intermediate goals:
Generally speaking, on each line each cell depends on the cells on its left, and in each column, each cell depends on the cells above it. So, G1.PSA is the root of the dependency graph.
However, this matrix is only a simplified view and we can usefully sub-divide the first line (TL) and the last column (TLS).
Indeed TL can be divided in TL-ecdh, TL-ecdsa, TL-ecjpake; then full TL means not only being able to build and work with any one of these modules disabled, but all of them disabled simultaneously. As of end of March 2023:
all.sh
componenttest_psa_crypto_config_accel_ecdh
;Note that ECPa is a stepping stone towards ECPf, which already brings a significant code size benefit, as curve arithmetic is about 5kB.
Note: as part of ECPf (previously CV), we'll probably want to define new feature macros for curves, most probably in
pk.h
(see this comment).Finally, TLS can be sub-divided, first by TLS version, then by key exchange type, giving intermediate goals such as TL-ecdh.TLS.12.ECDHE-PSK which means supporting the TLS 1.2 ECDHE-PSK key exchange when
MBEDTLS_ECDH_C
is disabled. Interestingly, this sub-goal only depends on TL-ecdh.PSA, not TL-ecdh.PK or TL-ecdh.X509, as neither PK nor X.509 is involved in this particular TLS 1.2 key exchange.Note that some cells (or sub-divided goals) will require specific work beyond satisfying their dependencies, while it is expected that some cells won't. For example, as far as I can see now, ECPf.X509 should be reached automatically with no additional work once ECPf.PK and TL.X509 are done; similarly TL.X509 should follow from TL.PK with no additional work.
The following sub-sections make a more detailed review of the dependencies of each TLS 1.2 and 1.3 key exchange, then of each module in general.
Dependencies of the TLS 1.2 key exchanges
MBEDTLS_KEY_EXCHANGE_RSA
: X.509, PK (RSA)MBEDTLS_KEY_EXCHANGE_DHE_RSA
: X.509, PK (RSA), DHM, Bignum (see below)MBEDTLS_KEY_EXCHANGE_ECDHE_RSA
: X.509, PK (RSA), ECDHMBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
: X.509, PK (ECDSA), ECDHMBEDTLS_KEY_EXCHANGE_PSK
: crypto core only (not even PK)MBEDTLS_KEY_EXCHANGE_DHE_PSK
: DHM, Bignum (see below)MBEDTLS_KEY_EXCHANGE_RSA_PSK
: X.509, PK (RSA)MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
: ECDH (no PK, no X.509)MBEDTLS_KEY_EXCHANGE_ECDH_RSA
: ECDH, X.509, PK (RSA), ECP (see below)MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA
: ECDH, X.509, PK (ECDSA), ECP (see below)MBEDTLS_KEY_EXCHANGE_ECJPAKE
: ECJPAKE only (no PK, no X.509)Among those relevant for the current work (that is, excluding RSA, DHE-RSA, PSK, DHE-PSK, RSA-PSK which have no ECC component), two stand out for having fewer dependencies, in particular not depending on PK: ECJPAKE and ECDHE-PSK.
Dependencies of the TLS 1.3 key exchange modes
KEY_EXCHANGE_MODE_PSK
: crypto core only (not even PK)KEY_EXCHANGE_MODE_EPHEMERAL
: ECDH, X.509, PK (RSA or ECDSA)KEY_EXCHANGE_MODE_PSK_EPHEMERAL
: ECDH (no PK or X.509)Pure PSK is hardly relevant for the current work, having no ECC component; among the other two, PSK-EPHEMERAL stands out as having fewer dependencies, in particular not depending on PK or X.509.
Direct dependencies of TLS on ECP or Bignum
In principle, TLS should only depend on high-level algorithms (ECDSA, ECDH, ECJPAKE, using the PSA APIs when MBEDTLS_USE_PSA_CRYPTO is defined) and modules (X.509, PK). It should not make direct use of low-level modules such as ECP and Bignum.
However it currently directly calls the following low-level functions:
- has been fixed by Remove uses of mbedtls_ecp_curve_info in TLS (with USE_PSA) #6830mbedtls_ecp_curve_info_xxx()
mbedtls_ecp_point_write_binary()
andmbedtls_ecp_write_key()
- see driver-only ECC: TLS: avoid use ofmbedtls_ecp_point_write_binary()
(withUSE_PSA
) #7405 and driver-only ECC: TLS: avoid use ofmbedtls_ecp_write_key()
(withUSE_PSA
) #7406- only for DHM (formbedtls_mpi_free()
,mbedtls_mpi_read_binary()
mbedtls_ssl_conf_dh_param_xxx()
), so out of scope herembedtls_mpi_bilen()
inmbedtls_debug_print_mpi()
, used by a number of debug functions all the way up the stack (see reverse call graph below). Some of these functions are also associated with legacy types (mbedtls_ecp_point
etc.). The functions are not called directly from SSL code, but via macros (seessl_debug.h
). Fortunately, debug messages are not covered by the stability guarantee and can change if needed.Direct dependencies of X.509 on ECP or Bignum
In principle, X.509 should only depend on PK, and not directly call any function from ECP or Bignum.
It indeed does not make any direct call to ECP, however it optionally makes direct calls to Bignum (or associated)
fixed by Improve X.509 cert writing serial number management #6843 (making the call optional)mbedtls_mpi_copy()
,mbedtls_mpi_free()
,mbedtls_mpi_init()
,mbedtls_asn1_write_mpi()
Dependencies of PK
Crypto computations themselves should be fine, but parsing & writing not so much- this has been addressed in #7073 and #7074 and #7682. See also #7570 for a design rationale.Note: after #7682, if my investigations with
unifdef
are correct, PK no longer has any direct dependency on Bignum whenECP_C
is removed (and support for ECC comes from PSA).Dependencies of PSA crypto
As of Mbed TLS 3.3, in builds where both ECDH and ECDSA are accelerated (edit: actually when
KEY_TYPE_ECC_KEY_PAIR
andKEY_TYPE_ECC_PUBLIC_KEY
are accelerated) we're getting failures intest_suite_psa_crypto
: basically,mostall cases ofderive_key_type
andderive_key
using ECC failwhile for some reason cases using(edit: that was a false negative which has been fixed by #6873).derive_key_exercise
passThis is a consequence of the fact that we haven't fully implemented driver support for cooked key derivation yet. The current plan is to accept that as a feature gap in accelerated ECC builds, until driver support for cooked key derivation is added. Note: this has been partially addressed in #7192 - the partial fix means it won't be a problem for TL or ECPa, but starting from ECP we'll have to accept a feature gap there.
The text was updated successfully, but these errors were encountered: