Wow! First, thanks for this extensive feedback! That's very helpful, and appreciated.
I'm going to reply to a few points. On a general note, you can see headlines for the main topics we're currently planning to work on in the Mbed TLS roadmap at https://developer.trustedfirmware.org/w/mbed-tls/roadmap/ . Please note that everything I write is based on current plans, which may change through the TrustedFirmware planning process or if real life shows that a current plan is not doable.
Over time, we're transitioning the API for the crypto part of the library from the current mbedtls_xxx functions to psa_xxx, which have a somewhat different philosophy: less exposure of internals, more protection against misuse, no reliance on malloc. Mbed TLS 3.0 will start the transition.
On 14/04/2020 21:10, Torsten Schuetze via mbed-tls wrote
1. I really missed an Initialize, Update, Finalize (IUF) interface for
CCM.
For GCM, we have mbedtls_gcm_init(), mbedtls_gcm_setkey(),
mbedtls_gcm_starts(), mbedtls_gcm_update() iterated,
mbedtls_gcm_finish(), mbedtls_gcm_free() or the comfort functions
mbedtls_gcm_crypt_and_tag() and mbedtls_gcm_auth_decrypt(). For
CCM, only mbedtls_ccm_init(), mbedtls_ccm_setkey(),
mbedtls_ccm_encrypt_and_tag() or mbedtls_ccm_auth_decrypt() and
mbedtls_ccm_free(). With this interface it was only possible to
encrypt and tag 128 kByte on my target system, while with GCM I
could encrypt much larger files.
see Github issue #662 and my comment there
In Mbed TLS 3.0, mbedtls_ccm_xxx() will not be a public interface anymore. We are planning to add support for multipart CCM in the psa_aead_xxx() interface (the prototypes are already in psa/crypto.h but their implementation is planned for some time in the next few months). We are not currently planning to add support for multipart CCM through mbedtls_cipher_xxx(), which in Mbed TLS 3 will be legacy functions. However, we would probably accept such support if it was contributed externally.
2. The next step, of course, is to integrate this into the higher
mbedtls_cipher layer.
Regarding higher, abstract layers: I often didn't understand which
interface I was supposed to use. In general, I like to use the
lowest available interface, for example, #include
"mbedtls/sha512.h" when I want to use sha512. However, if I need
HMAC-SHA-512 or HKDF-HMAC-SHA-512 then I have to use the interface
in md.h. For hash functions this is fine. Almost all hash functions
are supported via md.h. (I missed SHA-512/256 which is sometimes
preferable to SHA-256 on 64bit systems).
But with cipher.h, I can only access Chacha20Poly1305 and AES-GCM,
not AES-CCM.
In Mbed TLS 3, there will generally be a single public layer. Exposing lower layers helps with code size on resource-constrained devices, but it also has downsides, including locking down the APIs.
4. That I couldn't configure AES-256 only, i.e. without AES-128 and
AES-192, was to be expected (and the code overhead is not that
much). But in modern modes of operations nobody needs AES
decryption, only the forward direction. Sometimes modern
publications as Schwabe/Stoffelen "All the AES you need on
Cortex-M3 and M4" provide only the forward direction.
So, it would be fine if one could configure an AES (ECB) encryption
only without decryption.
Of course, this is only possible if we don't use CBC mode, etc.
This wouldn't only save the AES decryption code but also the rather
large T-tables for decryption.
For information, there is a branch of Mbed TLS called "baremetal", forked from Mbed TLS 2.16, which you can find on GitHub: https://github.com/ARMmbed/mbedtls/blob/baremetal . This branch is optimized for small code size, sometimes at the expense of speed and often at the expense of features. It has build options MBEDTLS_AES_ONLY_ENCRYPT and MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH. However I would not recommend using it in production because Arm (who still maintain this branch even after Mbed TLS itself has moved to TrustedFirmware) does not make any promise of stability. A feature that you rely on may be removed without notice.
I mention this branch because eventually, we do plan to port the improvements that don't sacrifice features to the Mbed TLS development branch. I can't give a timeline for this however.
With the current Mbed TLS, if you don't use CBC, I think you can save some code in aes.o by defining MBEDTLS_AES_DECRYPT_ALT and MBEDTLS_AES_SETKEY_DEC_ALT and providing functions mbedtls_aes_setkey_dec() and mbedtls_internal_aes_decrypt() that do nothing.
5. Regarding AES or better the AES context-type definition
[snip]
6. In general, the contexts of mbedTLS are rather full of
implementation specific details. Most extreme is mbedtls_ecp_group
in ecp.h. Wouldn't it be clearer if one separates the standard
things (domain parameters in this case) from implementation
specific details?
As a general design principle, context types in Mbed TLS 3 will be opaque. This will let us, for example, redesign mbedtls_aes_context and mbedtls_cipher_context.
9. Regarding ECC examples: I found it very difficult that there isn't
a single example with known test vectors as in the relevant crypto
standards, i.e. FIPS 186-4 and ANSI X9.62-2005, with raw public
keys. What I mean are (defined) curves, public key value Q=(Qx,Qy)
and known signature values r and s. In the example ecdsa.c you
generate your own key pair and read/write the signature in
serialized form. In the example programs/pkey/pk_sign.c and
pk_verify.c you use a higher interface pk.h and keys in PEM format.
So, it took me a while for a program to verify (all) known answer
tests in the standards (old standards as ANSI X9.62 1998 have more
detailed known answer tests). One needs this interface with raw
public keys for example for CAVP tests, see The FIPS 186-4 Elliptic
Curve Digital Signature Algorithm Validation System (ECDSA2VS).
11. In the moment, there is no single known answer tests for ECDSA
(which could be activated with #define MBEDTLS_SELF_TEST). I
wouldn't say that you need an example for every curve and hash
combination, as it is done in ECDSA2VS CAVP, but one example for
one of the NIST curves and one for Curve25519 and - if I have a
wish free - one for Brainpool would be fine. And this would solve
#9 above.
I don't get the point here. ECDSA is randomized, so you can't have a known answer test. The test suite does have known answer tests for deterministic ECDSA.
10. While debugging mbedtls_ecdsa_verify() in my example program, I
found out, that the ECDSA, ECC and MPI operations are very, let's
say, nested. So, IMHO there is a lot of function call overhead and
special cases. It would be interesting to see what's the
performance impact of a clean, straight-forward
mbedtls_ecdsa_verify without restartable code, etc. to the current
one.
As far as I remember, the refactoring done to add the restartable code had no measurable impact on performance. What does have a significant impact on performance is that the bignum module uses malloc all the time. We would like to completely rewrite bignum operations at some point during the 3.x series, not only for performance but also because its design makes it hard not to leak information through side channels.
12. Just a minor issue: I only needed ECDSA signature verification,
therefore I only included MBEDTLS_ASN1_PARSE_C. But it is not
possible to compile without MBEDTLS_ASN1_WRITE_C needed for ECDSA
signature generation.
I'm not sure if I've written it down anywhere, but I'd like to remove the dependency of ECDSA on ASN1 altogether. Parsing and writing a SEQUENCE of two INTEGERs can be done with ad hoc code. Likewise for what little ASN1 the RSA module uses. And then asn1*.o can move out of libmbedcrypto and libpsacrypto, and into libmbedx509 where it belongs.
Having only signature verification would be useful, indeed. That may happen with the bignum rewrite I mentioned above, if signature verification ends up using some faster non-constant-time code (this is also relevant for #13).
14. Design question: In the moment, both GCM and CCM use their own
implementation of CTR encryption which is very simple. But then we
have mbedtls_aes_crypt_ctr() in aes.h which is very simple, too.
Let's assume at one day we have a performance optimized CTR
encryption (for example from Schwabe & Stoffelen) with all fancy
stuff like counter-mode caching etc. Then this would have to be
replaced at three places at minimum. While isn't the code at this
point more modularized? Is this a dedicated design decision?
Having a single implementation of CTR is on the PSA roadmap because if there's a hardware accelerator that does it, we want to use it everywhere it's relevant.
In Mbed TLS (or more precisely in its ancestor PolarSSL, if not _its_ ancestor XySSL), there was a conscious design decision to make each .c file as independent from the others as possible, which explains why camellia_ctr is completely independent from aes_ctr. But I don't know why ccm and gcm reimplement ctr.
Why do I find at so many places
for( i = 0; i < 16; i++ )
y[i] ^= b[i];
instead of a fast 128-bit XOR macro with 32bit aligned data?
As a programmer who doesn't write compilers, I think this is the right way to xor 16 bytes, and it's the compiler's job to optimize it to word or vector operations if possible. Admittedly this does mean the compiler has to know that the data is well-aligned, which can be hard to guarantee and easy to forget.
So, that's it for the moment. I hope I could give some hints for the
further development of mbedTLS. Feel free to discuss any of the above
points. It's clear to me that we cannot have both: clear and simple to
understand code and performance records.
Right. Also maintainable code and minimal code size, because minimal code size comes from letting the application developer #ifdef out everything that they don't care about, but this is a nightmare to test. It's one of the topics we're thinking about for Mbed TLS 3 and beyond.
In general, Mbed TLS is primarily targeted at embedded systems, and is likely to privilege 1. security (including side channel resistance) and 2. code size. This doesn't mean that we don't care about performance, just that it isn't our top priority. That being said, we also do have some code that's optimized for performance (without compromising security) and not code size: the library already includes X25519 from Project Everest (https://project-everest.github.io/) (turn it on with MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED). This is code that's formally proven not only for functional correctness, but also for side channel resistance; the implementation has aggressive inlining which makes it very fast, but obviously also large in terms of code size. Hopefully other algorithms will follow soon.
Ciao,
Torsten
Once again, thanks for the detailed feedback, and I hope we can improve Mbed TLS for everyone!
--
Gilles Peskine
Mbed TLS developer
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
Hi all,
I would like to bring up the following:
(How) Shall the APIs for PSKs and TLS session resumption be modified in Mbed TLS 3.0?
The motivation for this question is the consolidation of PSKs, ticket-based resumption
and session-id-based resumption in TLS 1.3. Now, while there will be no TLS 1.3 support
in Mbed TLS 3.0 as it stands, I think it would be beneficial to make the API amenable
to TLS 1.3 as much as possible already now.
Finding the right API here is non-trivial, and I'll describe first how the
current API works and how TLS 1.2 and 1.3 differ, before making suggestions
on how the Mbed TLS 3 API might look like. The mail is therefore quite long,
but I hope you'll bear with me.
# Session Resumption in Mbed TLS 2.X
Recall how resumption works in Mbed TLS 2.X on the client:
1. Establish a connection as usual
2. Store established session for later re-use
`mbedtls_ssl_session_save()` saves connection parameters relevant for
session resumption in an instance of `mbedtls_ssl_session`.
Optional:
2.1: Serialize session for offline storage
2.2: Deserialize session
3. Loading a stored session
`mbedtls_ssl_session_load()` is called on the stored session after initialization
and before running the handshake via `mbedtls_ssl_handshake()`.
4. Connect using stored session
Run `mbedtls_ssl_handshake()` as usual.
To my knowledge, the following is transparent to the user:
* The means by which resumption is achieved, which can be either id- or ticket-based.
* Whether the session was resumed or not - there is a silent fallback to a full
handshake when session resumption is rejected by the server.
On the server, ticket- and id-based resumption are configured independently as follows:
- ID-based resumption is controlled via `mbedtls_ssl_conf_session_cache()`
- Ticket-based resumption is controlled via `mbedtls_ssl_conf_session_tickets_cb()`.
# PSKs in Mbed TLS 2.X
Coming to PSKs: First, recall that, under the hood, resumed connections establish
a master secret purely on the basis of a previous master secret, without resorting to
asymmetric crypto. The same is true for PSK-based connections, and this observation is
embodied in TLS 1.3 which, as mentioned, consolidates resumption and PSKs.
In TLS 1.2, though, PSKs and session resumption are different, and consequently
Mbed TLS handles them through a separate API `mbedtls_ssl_conf_psk()`, which
takes the PSK identifier and the PSK itself.
Side-question: Should this apply to the SSL configuration or the SSL context?
It seems to me that somebody might want to run multiple PSK-based
connections with different PSKs, but same configuration otherwise.
At the moment, this would require a configuration per connection.
Maybe this decision of what belongs at the level of the config
could be thoroughly discussed independently?
# PSKs in TLS 1.3
In TLS 1.3, all kinds of resumptions are hanlded ander the umbrella of PSKs:
The client offers PSK identities in its ClientHello, the server picks one or
leaves it, and the master secret for the connection is derived from the PSK
associated with the PSK identity.
Underlying this is some form of translation
`PSK-Identity -> PSK`
on the server which allows to derive the PSK from the PSK identity.
How this mapping is realized is entirely implementation-specific,
but it can take at least the following forms, giving back all forms
of session resumption:
- 'PSK Identity -> PSK' via database lookup:
This subsumes classical PSKs and ID-based resumption,
since the data necessary to resume a session is stored
on the server.
- 'PSK Identity -> PSK' via AEAD:
The PSK can be encoded in the PSK identity itself by using some
authenticated encryption of the PSK as the PSK identity, the key
for which resides on the server.
This subsumes Ticket-based resumption.
There are the following noteworthy differences, though:
1. In TLS 1.2, the server provides a 'PSK identity hint' and the
client picks a particular PSK identity. In TLS 1.3, the client
offers a _list_ of PSKs, and the server picks one or none.
2. In TLS 1.2, the server can issue only a single session ticket.
In TLS 1.3, the server can issue as many session tickets as
he wishes, and the client can use any of those for later
session resumption.
This has the following consequences for the API:
1. The PSK-configuration API must allow the configuration
of multiple PSKs on the client.
2. There must be a means to export more than one session ticket
for later resumption.
# API considerations for Mbed TLS 3.X
## Part 1: Load/Save API
In essence, keep the flow of `mbedtls_ssl_session_load/save()`,
but make the following adjustments. Whether the target structure
remains `mbedtls_ssl_session` and how it looks like internally
isn't relevant at this point and is up to discussion.
1. It must be possible 'save' a session multiple times, which
in TLS 1.3 amounts to exporting the tickets issued by the
server one-by-one.
This can be realized in a variety of ways, for example:
- Allow calling `mbedtls_ssl_session_save()` multiple
times, and modify its semantics from the idempotent
nature of Mbed TLS 2.X to iterating through the available
tickets, and returning an error when no more tickets
are available.
This has the benefit that it likely requires no code
change for users migrating from Mbed TLS 2.X, since
a change is needed only when an application stores
a single session multiple times, which could be done
by calling `mbedtls_ssl_session_save()` multiple times
before, while now one would need to call it once and
manually replicate the obtained session structure.
On the negative side, this wastes memory for applications
not interested in session resumption, or those that only
need a single ticket. We don't want the server to be able
to flood the client with arbitrarily many tickets.
- Allow registering a callback that's triggered whenever
a new ticket arrives.
The drawback of this is that it is larger deviation
from the Mbed TLS 2.X API. On the positive side, applications
that don't need tickets, or only need a limited number of
such, can simply drop further tickets and thereby prevent
allocating RAM for them.
2. It must be possible to 'load' multiple sessions, meaning
that the client should offer any of them to the server for
resumption.
## Part 2: Consolidation with PSK
Make it possible to setup an `mbedtls_ssl_session` (or whatever
it will be called) structure manually from an externally PSK
provisioned PSK, and allow loading this session for resumption
as above, via one of potentially many calls to `mbedtls_ssl_session_load()`.
There are multiple variants to this, for example:
1. Make `mbedtls_ssl_session` transparent so users can build
it manually by filling the respective fields.
2. Provide a helper API to build a session from a PSK.
The old API `mbedtls_ssl_conf_psk()` can then be _derived_ from
this for convenience, building a session from the provided PSK
and loading it, in a single API.
Before going into further details and making the mail even
longer: What do you think of this approach? Do you see
alternatives?
Best,
Hanno
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
On 15/04/2020 22:00, Gilles Peskine wrote:
> Wow! First, thanks for this extensive feedback! That's very helpful,
> and appreciated.
> ...
Thank you for your reply.
> Over time, we're transitioning the API for the crypto part of the
> library from the current mbedtls_xxx functions to psa_xxx, which have
> a somewhat different philosophy: less exposure of internals, more
> protection against misuse, no reliance on malloc. Mbed TLS 3.0 will
> start the transition.
>
> On 14/04/2020 21:10, Torsten Schuetze via mbed-tls wrote
>> 1. I really missed an Initialize, Update, Finalize (IUF) interface for
>> CCM.
>>
>> see Github issue #662 and my comment there
>
> In Mbed TLS 3.0, mbedtls_ccm_xxx() will not be a public interface
> anymore. We are planning to add support for multipart CCM in the
> psa_aead_xxx() interface (the prototypes are already in psa/crypto.h
> but their implementation is planned for some time in the next few months).
Ah, okay, I saw the interface but missed the implementation. This
explains all.
> We are not currently planning to add support for multipart CCM through
> mbedtls_cipher_xxx(), which in Mbed TLS 3 will be legacy functions.
> However, we would probably accept such support if it was contributed
> externally.
Don't know if Corona takes soo long that I'll have time for that ;-(.
We'll see.
>> 2. The next step, of course, is to integrate this into the higher
>> mbedtls_cipher layer.
>>
>> Regarding higher, abstract layers: I often didn't understand which
>> interface I was supposed to use.
> In Mbed TLS 3, there will generally be a single public layer. Exposing
> lower layers helps with code size on resource-constrained devices, but
> it also has downsides, including locking down the APIs.
I don't mind if there are two accessible layers. In many crypto libs you
have an expert layer and a simple layer. Hope this public layer doesn't
get too abstract.
>> 4. That I couldn't configure AES-256 only, i.e. without AES-128 and
>> AES-192, was to be expected (and the code overhead is not that
>> much).
> For information, there is a branch of Mbed TLS called "baremetal",
> forked from Mbed TLS 2.16, which you can find on GitHub:
> https://github.com/ARMmbed/mbedtls/blob/baremetal . This branch is
> optimized for small code size, sometimes at the expense of speed and
> often at the expense of features. It hasbuild options
> MBEDTLS_AES_ONLY_ENCRYPT and MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH.
> However I would not recommend using it in production because Arm (who
> still maintain this branch even after Mbed TLS itself has moved to
> TrustedFirmware) does not make any promise of stability. A feature
> that you rely on may be removed without notice.
Okay, thanks for this information. In the moment, I can live with the
current situation. With a smaller Cortex M3 I would probably switch.
> I mention this branch because eventually, we do plan to port the
> improvements that don't sacrifice features to the Mbed TLS development
> branch. I can't give a timeline for this however.
>
> With the current Mbed TLS, if you don't use CBC, I think you can save
> some code in aes.o by defining MBEDTLS_AES_DECRYPT_ALT and
> MBEDTLS_AES_SETKEY_DEC_ALT and providing functions
> mbedtls_aes_setkey_dec() and mbedtls_internal_aes_decrypt() that do
> nothing.
This is a clever trick. I'll remember that for the next application.
>> 5. Regarding AES or better the AES context-type definition
>>
>> [snip]
>>
>> 6. In general, the contexts of mbedTLS are rather full of
>> implementation specific details. Most extreme is mbedtls_ecp_group
>> in ecp.h. Wouldn't it be clearer if one separates the standard
>> things (domain parameters in this case) from implementation
>> specific details?
>
> As a general design principle, context types in Mbed TLS 3 will be
> opaque. This will let us, for example, redesign mbedtls_aes_context
> and mbedtls_cipher_context.
Hmm, this just means that you access it with dedicated functions only
and that the internals can change at any time. Empirical knowledge shows
that some people will nevertheless use the internal structure (I
remember TLS session tickets which shall be opaque, too. But many
implementations rely on that internal structure)
>> 9. Regarding ECC examples: I found it very difficult that there isn't
>> a single example with known test vectors as in the relevant crypto
>> standards, i.e. FIPS 186-4 and ANSI X9.62-2005, with raw public
>> keys. What I mean are (defined) curves, public key value Q=(Qx,Qy)
>> and known signature values r and s. In the example ecdsa.c you
>> generate your own key pair and read/write the signature in
>> serialized form. In the example programs/pkey/pk_sign.c and
>> pk_verify.c you use a higher interface pk.h and keys in PEM format.
>>
>> So, it took me a while for a program to verify (all) known answer
>> tests in the standards (old standards as ANSI X9.62 1998 have more
>> detailed known answer tests). One needs this interface with raw
>> public keys for example for CAVP tests, see The FIPS 186-4 Elliptic
>> Curve Digital Signature Algorithm Validation System (ECDSA2VS).
>> 11. In the moment, there is no single known answer tests for ECDSA
>> (which could be activated with #define MBEDTLS_SELF_TEST). I
>> wouldn't say that you need an example for every curve and hash
>> combination, as it is done in ECDSA2VS CAVP, but one example for
>> one of the NIST curves and one for Curve25519 and - if I have a
>> wish free - one for Brainpool would be fine. And this would solve
>> #9 above.
>>
>
>
> I don't get the point here. ECDSA is randomized, so you can't have a
> known answer test. The test suite does have known answer tests for
> deterministic ECDSA.
This remark is also useful for your thread Running Mbed TLS unit tests
on embedded targets
Okay, my fault. I didn't explain it correctly.
In this context, I was only talking about ECDSA signature verification.
And this is, of course, deterministic. Specifically, I wanted to use the
CAVP test from SigVer.rsp in 186-3ecdsatestvectors.zip. My strategy
with NIST CAVP tests is, that I take the simple response files (text)
and built just with search and replace a structure that can be compiled
within a program. So, no file system access, no perl or python (at least
not at the target system). In the ECDSA case, this looks like
struct {
const char *msg; /* message as hex string */
const char *Qx; /* public key, x-coordinate as hex string */
const char *Qy; /* public key, y-coordinate as hex string */
const char *r; /* signature r as hex string */
const char *s; /* signature s as hex string */
int Result; /* 1 on expected fail or 0 on expected success */
} ecdsa_verify_test[1] = {
{"9dd789ea25c04745d57a381f22de01fb0abd3c72dbdefd44e43213c189583eef85ba662"
"044da3de2dd8670e6325154480155bbeebb702c75781ac32e13941860cb576fe37a05b7"
"57da5b5b418f6dd7c30b042e40f4395a342ae4dce05634c33625e2bc524345481f7e253"
"d9551266823771b251705b4a85166022a37ac28f1bd",
"cb908b1fd516a57b8ee1e14383579b33cb154fece20c5035e2b3765195d1951d75bd78f"
"b23e00fef37d7d064fd9af144",
"cd99c46b5857401ddcff2cf7cf822121faf1cbad9a011bed8c551f6f59b2c360f79bfbe"
"32adbcaa09583bdfdf7c374bb",
"33f64fb65cd6a8918523f23aea0bbcf56bba1daca7aff817c8791dc92428d605ac629de"
"2e847d43cee55ba9e4a0e83ba",
"4428bb478a43ac73ecd6de51ddf7c28ff3c2441625a081714337dd44fea8011bae71959"
"a10947b6ea33f77e128d3c6ae",
0},
};
/* example 2 [P-384,SHA-384] from SigVer.rsp 186-3ecdsatestvectors.zip */
And for this, I couldn't find any example with mbedTLS. It isn't that
difficult, but as always with ECC you have several interfaces to consider.
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
mbedtls_ecp_point_init(&Q);
mbedtls_ecdsa_init(&ctx);
mbedtls_ecp_group_init(&ctx.grp);
ret = mbedtls_ecp_group_load(&ctx.grp, ECPARAMS);
/* load domain parameters for named curve */
if (verbosity != 0)
mbedtls_printf(
"-------------------- ECDSA verify testing
-------------------\r\n");
/* hash message */
(void)hexstring2bytestring((unsigned char *)ecdsa_verify_test[0].msg,
(unsigned int)strlen(ecdsa_verify_test[0].msg),
byte_string);
if ((ret = mbedtls_sha512_ret((unsigned char *)byte_string,
strlen(ecdsa_verify_test[0].msg) / 2,
sha512sum, is384)) != 0)
ref_test_error = 1;
memcpy(sha384sum, sha512sum, 48);
/* sha384sum contains SHA-384(msg) */
(void)string2hexstring(sha384sum_hex, sha512sum, 48);
/* load public key */
ret = mbedtls_ecp_point_read_string(&Q, 16, ecdsa_verify_test[0].Qx,
ecdsa_verify_test[0].Qy);
ret = mbedtls_ecp_check_pubkey(&ctx.grp, &Q);
/* check public key */
ret = mbedtls_mpi_read_string(&r, 16, ecdsa_verify_test[0].r);
ret = mbedtls_mpi_read_string(&s, 16, ecdsa_verify_test[0].s);
/* set signature value */
ret = mbedtls_ecdsa_verify(&ctx.grp, sha384sum, sizeof(sha384sum), &Q, &r,
&s);
/* verify signature */
Most crypto standards have KATs in this raw form. With the structure
above (it even works for very long strings, at least with gcc), you just
copy and paste. And the code compiles. The mbedTLS unit test examples
in tests/suites/test_suite_ecdsa.data or test_suite_ecdsa.function are
similar, but not self explaining and (data) cannot be compiled on
their own.
In this way, I implemented all relevant CAVP tests for me. And they fit
onto the target (Cortex M4 with 384 kB RAM). On a smaller M3 smart card
processor, you often have problems with code size and/or RAM.
To be honest, I didn't look into the mbedTLS unit tests very deeply. I
just implemented the necessary CAVP for me.
Regarding (deterministic) ECDSA and examples. Of course, classical ECDSA
is randomized. Often, there is at least one example in the standards
with fixed ephemeral key k and all intermediate values. This would be a
KAT for me. I know that it is dangerous to fix an ephemeral key (Sony
play station desaster), but for testing it is sometimes necessary.
Obviously, you or mbedTLS prefers deterministic ECDSA over classical
ECDSA. But with deterministic ECDSA you have other problems as fault
attacks. We had a discussion about this at the NIST ECC Workshop in 2015
or 16, I think. Shortly thereafter, there were the first attacks against
EdDSA etc. So, if you can't handle random numbers/ephemeral keys you
shouldn't do crypto. All countermeasures against full power analysis
nowadays use random masking.
(I confess, I'm a little bit biased. I do RNG evaluation most of the time)
>
>> 10. While debugging mbedtls_ecdsa_verify() in my example program, I
>> found out, that the ECDSA, ECC and MPI operations are very, let's
>> say, nested. So, IMHO there is a lot of function call overhead and
>> special cases. It would be interesting to see what's the
>> performance impact of a clean, straight-forward
>> mbedtls_ecdsa_verify without restartable code, etc. to the current
>> one.
>
> As far as I remember, the refactoring done to add the restartable code
> had no measurable impact on performance. What does have a significant
> impact on performance is that the bignum module uses malloc all the
> time. We would like to completely rewrite bignum operations at some
> point during the 3.x series, not only for performance but also because
> its design makes it hard not to leak information through side channels.
The mbedTLS mpi design is inspired by GMP, right? Some years ago, when
microprocessors were smaller and/or malloc was strictly forbidden within
deeply embedded devices (automotive) I liked the MIRACL mpi design very
much. Or the good old Fortran way (one huge work array, index
calculation by hand). Just joking.
>
>> 12. Just a minor issue: I only needed ECDSA signature verification,
>> therefore I only included MBEDTLS_ASN1_PARSE_C. But it is not
>> possible to compile without MBEDTLS_ASN1_WRITE_C needed for ECDSA
>> signature generation.
>
> I'm not sure if I've written it down anywhere, but I'd like to remove
> the dependency of ECDSA on ASN1 altogether. Parsing and writing a
> SEQUENCE of two INTEGERs can be done with ad hoc code. Likewise for
> what little ASN1 the RSA module uses. And then asn1*.o can move out of
> libmbedcrypto and libpsacrypto, and into libmbedx509 where it belongs.
I completely agree with you. ASN.1 isn't crypto (and there was a time
when every two or three weeks, there was a bug in ASN.1 parsing). But I
don't know where to draw the line between raw public keys and
PEM/DER/PKCS#8, for example.
>> Why do I find at so many places
>>
>> for( i = 0; i < 16; i++ )
>> y[i] ^= b[i];
>>
>> instead of a fast 128-bit XOR macro with 32bit aligned data?
>
> As a programmer who doesn't write compilers, I think this is the right
> way to xor 16 bytes, and it's the compiler's job to optimize it to
> word or vector operations if possible. Admittedly this does mean the
> compiler has to know that the data is well-aligned, which can be hard
> to guarantee and easy to forget.
Okay, then I'm qualified to write compilers now ;-) May be I was
working on crypto hardware with fixed registers for too long. But if you
look at Microsoft's SymCrypt you'll find exactly this in
SymCryptXorBytes() and they use it a lot in their crypto. I liked their
comment: If your data is not aligned, then you don't care for performance.
> Right. Also maintainable code and minimal code size, because minimal
> code size comes from letting the application developer #ifdef out
> everything that they don't care about, but this is a nightmare to
> test. It's one of the topics we're thinking about for Mbed TLS 3 and
> beyond.
>
> In general, Mbed TLS is primarily targeted at embedded systems, and is
> likely to privilege 1. security (including side channel resistance)
> and 2. code size. This doesn't mean that we don't care about
> performance, just that it isn't our top priority.
I hope I haven't been misunderstood. We choose mbedTLS in the first
place because of its modular structure. I wouldn't have had a chance to
port all the crypto of OpenSSL, for example, to my SoC. There is a fine
balance between performance and simplicity/maintainability/portability.
> Once again, thanks for the detailed feedback, and I hope we can
> improve Mbed TLS for everyone!
>
> --
> Gilles Peskine
> Mbed TLS developer
>
Thank you for your detailed answer. I thing I'll closely follow the Mbed
TLS development.
Torsten