-
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
issues migrating lighttpd mod_mbedtls to mbedtls 3.0.0 #5331
Comments
Thank you for the detailed feedback! I (or a fellow team member) will go through the list in more detail and file individual issues. It's going to take a while to resolve them all. We just had a code freeze for the 3.1 release and it's going to still be missing some public fields or accessor functions. The 2.28 version will remain supported for at least 3 years. A partial reply to some of your points:
Sorry. In our defense, this is the first incompatible release in 4 years. We needed to do some cleanup in TLS to prepare for adding TLS 1.3 support.
This is an identified gap which unfortunately missed the 3.1 window.
We can add an accessor function for this. I think its implementation will change with the planned rewrite of the TLS stack. In the meantime, can't you use the return value from
3.1 has accessor functions for this type.
Many fields of ASN.1 and X.509 parsing structures are public in 3.1. Please let us know if that's not enough.
I think that's a general problem with SSL config functions.
Unfortunately this is a major feature which is currently not on our roadmap. |
Thanks for the detailed response.
I totally understand incompatible changes in major version releases. My minor nit questions why
Would you accept patches to improve this? I mentioned this because I (now) reach into private
Hopefully this will give you an idea of how lighttpd is using mbedTLS, and please let me know if I am crazy and there are better ways to do this -- or if this might suggest there might be better ways that mbedTLS could handle this. The following is the comment I left myself in the code to try to explain why some hoop-jumping is done, and why
|
While I may have some technical criticisms, I do want to shout out that I believe mbedtls interfaces to, in general, be quite nice, and that the mbedtls documentation in the headers is fantastic! Were mbedtls not open source, I would not have been able to write lighttpd mod_mbedtls and integrate it as well with mbedtls. Thank you very much. |
It does not look like these changes were included in the
Not (yet?) enough to solve the issue I posted above. There is also no accessor funcs (see suggestion in my initial post) for access to retrive the
|
Would you like me to submit the following as pull requests? |
@gstrauss Yes please! With a unit test ( |
#5353 for memory leak if As for I am interested in your take on some of the more complex questions above before I attempt to craft patches for those. Thanks. |
@gstrauss Thank you so much for your feedback, that's extremely valuable! (And thanks for the kind words about the API and documentation, too.) I'll be creating individual issues based on your list (and, when possible, consolidating with feedback we received from other sources). I hope you won't mind it I annotate your list with references to issues created, that will help be keep track of what's done and what's left to do. Hopefully we can continue the discussion in the individual issues then. Again, thank you so much for your feedback! |
Not at all. Please do so as I am interested in following the issues. I'm eager to help submit some patches for review, and understand that there will be latency in scheduling. Before I spend time (which might turn out to be wasted) on larger patches, I am waiting for feedback on smaller patches, e.g. #5353, which while small, is also low priority. |
I'm afraid adding access to We're in the process of migrating the X.509 and TLS layers to use PSA Crypto APIs instead of the current This is one of the reasons why made most fields private by default: in order to give ourselves more freedom to modify the implementation. In this case, the obvious solution would be to take a step back and give you access directly to the information you actually want: the name and key size. This could be extracted from the ciphersuite. For example:
Would that work for you? By the way:
Also, while looking around I've seen that apparently nginx is extracting the key size from the ciphersuite name - I think we can agree this seems suboptimal and we'll try to provide a better API for that :) |
Thanks for pointing us to this comment. I don't think you're crazy, and clearly the situation with partial writes is a bit more complex than we'd all like it to be (I also have to spend some time thinking and reading the code again to clarify my understanding of the situation). I think there are two potential kinds of partial writes: (1) those at the TLS level (the requested length is large than the maximum fragment length for TLS), which I understand you're avoiding by always calling These correspond to the following paragraphs in the documentation:
If I understand correctly, one of the things you were saying even before 3.0, is that the requirement in the second paragraph (to call again with the same arguments) is inconvenient, and actually unnecessary because all the info is in the The other point, which causes issues with 3.0, is that you're currently using @hanno-arm You're probably more familiar than me with plans for improving the |
Actually, I was just thinking: would it work to just keep the existing callback, but make sure it's called after all the extensions have been processed? I think that would be a backwards compatible change (people can't reasonably rely on the fact that all extensions have not been processed, since the SNI extension could very well be the last one), and would give you the assurance you need, that from the SNI callback you can query the state of ALPN - we'd need to make sure
As Gilles said, full OCSP support is a major feature currently not on our roadmap, but I'm wondering it there is a small enough subset we could implement that would meet your needs for server-side stapling. I might be over-optimistic here, but perhaps there's a way we can keep handling of OCSP proper outside of Mbed TLS, and just handle the TLS extension itself: parse the client extension, invoke an application-provided callback to get the data to be stapled if any, then write the extension* back if applicable. That way, all the TLS layer has to do is generic extension handling and copying opaque bytes provided by the application, not having any knowledge of OCSP itself. Just thinking out loud, perhaps things are not so easy when looking deeper. But is there's a way to reduce the problem to something simple enough, and if you're interested in contributing a PR for that, then perhaps that could work. Otherwise, if more OCSP support is needed, then I'm afraid it's unlikely to happen soon, sorry. *Edit: I went and read RFC 6066 sec. 8, and actually the server does not respond with an extension, but with a new handshake message CertificateStatus inserted right after the Certificate message. That's a bit harder to implement than just returning an extension. But I'm still under the impression that the TLS stack does not need to know about OCSP, and can just pass opaque bytes around: from the ClientHello extension to the calback, and then from the callback to the CertificateStatus message. |
This is a behavior change, although since our documentation doesn't specify exactly when the various callbacks run, it wouldn't be a change in documented behavior and I'd be perfectly ok with doing this change in a non-LTS branch. Consider a server that is only intended to work with a specific client (not that rare in IoT) which happens to pass extensions in a certain order, and where the server runs two callbacks and expects them to be called in that order. If we change to running callbacks in an order that doesn't depend on what's on the write, this server may break. |
@mpg: Thank you for the deeper analysis. I am going to split the More important: use of If a write returns Later on, lighttpd checks The mbedtls implementation choice of For mbedtls 3.0.0, if
SNI is the very first extension added to TLS, and has TLS extension id 0. It is often the first extension provided, and other extensions may rely on SNI having been provided, e.g. extensions to ALPN. That is why my request is for an additional callback after all TLS extensions have been processed, and which can be used for certificate selection and for any other purposes after all TLS extensions have been processed. In the future, TLS ECH (encrypted client hello) might be handled here, too. To be crystal clear about the need for a callback after TLS extensions have been processed: if such a callback is not implemented, I expect to have to intercept and process the TLS client hello myself, before calling mbedtls, and I would prefer not to write portions of a custom TLS library separate from mbedtls!
Yes, I agree with this line of thinking. For server-side, minimal support would add OCSP stapling information to the Server Hello if the application provided OCSP stapling info along with certificate selection. TLSv1.2 permits OCSP stapling info for the leaf cert in the chain, while TLSv1.3 extends this to allow OCSP stapling info for each certificate in the chain. Server-side parsing of OCSP stapling info from client certificate authentication could be implemented later (and is not currently supported by lighttpd mod_mbedtls). Adding selective OCSP stapling support is more than a few lines of code and not a simple patch, but might be a more manageable chunk. I might attempt this in the future, though not in the near-term. |
Follow-up in PR #5417 |
Ok, just trying to sum up what hasn't been moved to its own issue/PR yet:
|
That's a good point. If several callbacks all want to be the last to run, obviously that won't work, and we'll need a separate callback for that. However, unless I missed something, we don't have any callback related to ALPN, and actually the SNI callback is the only callback related to a ClientHello extension (except for the PSK callback, but I really can't imagine someone using both with an interaction between them). So, I don't think ordering is an obstacle to the existing SNI callback playing the role of "end-of-ClientHello" callback. OTOH, perhaps there are situations where it's desirable to have an "end-of-ClientHello" callback that's called no matter what (that is, even if the ClientHello didn't include the SNI extension). The thing its, I'd like to avoid having more callbacks than necessary, as the complexity of testing and reasoning about the code tends to go up (often more than linearly) with the number of callbacks. OTOH, clearly we don't want to have less callbacks than necessary, if that results in situations like:
I want to re-assure you that we absolutely want to avoid that. I'm not pushing back against adding something to meet your needs, just trying to determine what is the best way to do that. |
Unless I'm mistaken, yes, " Here's my current reasoning for why
So, there's only one source of |
Assuming that is correct, then yes. I walked through the code, too, and I agree with your assessment in that scope. Related, I am still uneasy with the internals since other parts of the code theoretically can modify out_left. Overall, I am uneasy with the delayed-action and the return value from I would prefer more deterministic behavior. If out_left == 0 and I submit <= If I wanted to not rely on mbedtls for this, I might achieve this by writing my own f_send() to replace mbedtls_net_send(), and have my custom function buffer records and never return MBEDTLS_ERR_SSL_WANT_WRITE, and keep track myself and avoid calling |
Yes, end of ClientHello callback is very desirable. End of Client Hello callback called unconditionally was added in openssl 1.0.2 and I assure you that it has been put to good use. I loudly champion a similar addition to mbedtls.
I appreciate the conversation and do feel like I am being heard. Thank you. As extensions have been added to TLS, it has become clear that some extensions may depend on others. Unless I am mistaken, TLS extension ordering is not defined by the specification. Even were it required, then for security reasons, it should not be relied upon.
|
With the changes in mbedtls 3.0, lighttpd mod_mbedtls does not build. Among other reasons, MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO is not defined. Also, MBEDTLS_PRIVATE must be added in many places before lighttpd mod_mbedtls will build without warnings or errors. Some other migrations are necessary, too. In short, nobody is using lighttpd mod_mbedtls with mbedtls 3.0, because trying to do so does not work. I am capable of working around the missing MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO. ;) However, adding a compatibility [Edit:] What do you think of this? In my code, I ported existing use of MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO to values introduced in mbedtls 3.0, and have backward compatibility defines for when lighttpd mod_mbedtls is compiled against older versions. This is specific to lighttpd mod_mbedtls:
|
The proliferation of ASN.1 parsers is an historical source of security bugs. lighttpd is trying to use the [Edit:] Also, yes, |
|
Initially, I'm in favour, so I started writing up an ticket about that, trying to generalize, when I realized that I don't think it would be really that helpful: there were several instances of
So, providing a As you say, you (and hopefully other maintainers of software using Mbed TLS) are capable of working around the change on your own, so it's more about being friendly and avoiding the need to everyone to come up with their own work-around. But in that case, I'm now thinking that there's no way to make this transparent for everyone, because as there's no 1-1 correspondence between old and new codes (in either direction), different people will probably want to use different workarounds depending on how they used those specific error codes. So, I'm afraid I'm inclined to do nothing on our side here, and just let people implement workarounds that work for them, unless someone can suggest a better solution. |
That's the way it is. Please do keep this in mind for the future when planning to remove public values (including enums), as removing them causes code using them to fail to compile. This may be desirable to force changes, but if a compatible |
FYI: #4183 "Simplify SSL write API for Mbed TLS 3" requests enhancements to |
Ah, I remembered Hanno had some plans about that, but I didn't remember it was written down in an issue. Thanks for finding it. |
x-ref: "issues migrating lighttpd mod_mbedtls to mbedtls 3.0.0" Mbed-TLS/mbedtls#5331
remove use of ssl->out_left in mbedtls 3.0.0 Discussed in Mbed-TLS/mbedtls#5331, the current implementations of mbedtls_net_send() and mbedtls_net_recv() return MBEDTLS_ERR_SSL_WANT_WRITE only when there is a partial write (though there is theoretical issue if writes are mixed with TLS alerts) x-ref: "issues migrating lighttpd mod_mbedtls to mbedtls 3.0.0" Mbed-TLS/mbedtls#5331
With the release of mbedtls 3.2.0 which includes updates to address many of the issues raised herein, lighttpd mod_mbedtls no longer uses Any remaining loose ends can be followed up in new issues, but are not blocking lighttpd mod_mbedtls use of mbedtls 3.x APIs. |
Thanks for letting us know! And for all your contributions of course, very much appreciated! |
handle mbedtls 3.x partial write better by saving partial write bytes in hctx->pending_write only if mbedtls_ssl_write() returned MBEDTLS_ERR_SSL_WANT_WRITE (fixes crash due to subsequent NULL pointer read if mbedtls_ssl_write() error was MBEDTLS_ERR_SSL_WANT_READ) x-ref: "issues migrating lighttpd mod_mbedtls to mbedtls 3.0.0" Mbed-TLS/mbedtls#5331
I am a lighttpd developer and author of lighttpd mod_mbedtls TLS module. I have read through the migration guide and have some issues, feedback, and questions.
https://github.com/ARMmbed/mbedtls/blob/development/docs/3.0-migration-guide.md
This is a long list. I can break it into separate github issues if you like, but I hope to get some feedback before creating a large number of new github issues. Thank you.
minor nits and simple bugs
removal of
MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
is poor formWhile more detailed
MBEDTLS_ERR_SSL_*
values are now available (good),why was it necessary to remove
MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
and break existing usage? Some developers attempt to maintain software
which works across multiple (major) versions of mbedtls.
[edit: not doing anything in 3.x, keeping in mind for 4.0]
mbedtls_ssl_context
makesmajor_ver
andminor_ver
members privateIs there an accessor function in mbedTLS 3.0.0? Should there be? [edit: Access to TLS version #5407]
Separate bug: [edit:
mbedtls_ssl_get_version()
does not support TLS 1.3 #5406]const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl )
returns a string (which would then need to be parsed), and for some
reason is missing support for "TLSv1.3" (
MBEDTLS_SSL_MINOR_VERSION_4
)blockers: no alternative other than accessing private structures
mbedtls_ssl_handshake_step()
callers must usembedtls_ssl_context
ssl.state
but
mbedtls_ssl_context
state
member is now private. What gives? [edit: Introduce SSL getter API for handshake state #4383]old limitation: no interface for per
mbedtls_ssl_context
data ptr for SNI callback(only function is
mbedtls_ssl_conf_sni()
) [edit: Allow per-context SNI callback (state) #5413]old limitation, but biggest code mess for lighttpd supporting mbedtls:
library/ssl_srv.c:ssl_parse_client_hello()
design limitations:Certificate selection should be a separate callback, after all TLS extensions
have been parsed. Right now, SNI callback must select a certificate, and
IIRC, there may be problems/challenges trying to set the certificate again
if it should be changed. Please correct me if I am wrong, but TLS extensions
can occur in any order, so ALPN and SNI extensions might be received in any
order. lighttpd supports
RFC8737 "Automated Certificate Management Environment (ACME)
TLS Application-Layer Protocol Negotiation (ALPN) Challenge Extension"
and to support ALPN "tls-alpn-01" with mbedTLS, lighttpd must parse the
client hello for ALPN before
ssl_parse_client_hello()
, so that whenthe SNI extension is processed and callback executed, the proper certificate
is chosen, even if the ALPN extension comes after the SNI extension.
To parse the client hello, lighttpd forked and specialized
library/ssl_srv.c:ssl_parse_client_hello()
to handle the TLS ALPN extension.This is fragile, and will have to be done again with mbedTLS 3.0.0, where
more of the struct members and functions are now private and hidden.
Please suggest a better design in mbedTLS to support TLS ALPN "tls-alpn-01"
and please remedy the lack of per
mbedtls_ssl_context
data ptr for SNI callback(mentioned in the bullet point directly above).
Please add a new callback for certificate selection which occurs after all
TLS extensions have been processed, and along with enhancing the
SNI callback, allow the callback to be per
mbedtls_ssl_context
,not restricted to per
mbedtls_ssl_config
.[edit: https://github.com/Add certificate selection callback #5430]
partial writes
lighttpd uses
ssl.out_left
to detect partial writes.Please allow access or create inline accessor funcs.
https://git.lighttpd.net/lighttpd/lighttpd1.4/src/branch/master/src/mod_mbedtls.c#L1972
[edit: it looks like the return value of
ssl_write
is enough, after discussion]SSL tickets
mbedtls_ssl_ticket_context
members are now all private, but there are nointerfaces to manage it. lighttpd allows synchronization of session tickets
across multiple servers, and so writes into
mbedtls_ssl_ticket_context
tomanage
mbedtls_ssl_ticket_context
.lighttpd
mod_mbedtls_session_ticket_key_check()
https://git.lighttpd.net/lighttpd/lighttpd1.4/src/branch/master/src/mod_mbedtls.c#L335
[edit: Add access to some fields of
mbedtls_ssl_ticket
#5421]PEM file parsing
mbedtls_pem_context
members are now all privatelighttpd uses
mbedtls_pem_read_buffer()
to import a cert from memory.lighttpd then calls
mbedtls_x509_crt_parse_der_with_ext_cb()
to parse it,but must now use
pem.MBEDTLS_PRIVATE(buf), pem.MBEDTLS_PRIVATE(buflen)
Please allow access or create inline accessor funcs.
[edit: Allow access to result of PEM decoding #5414]
setting up a CGI environment
SSL_CIPHER
mbedtls_cipher_info_get_name(cipher_info)
SSL_CIPHER_ALGKEYSIZE
mbedtls_cipher_info_get_key_bitlen(cipher_info)
SSL_CIPHER_USEKEYSIZE (same as algkeysize with (most?) modern ciphers?)
These are possibly important to some people, though one may argue that keysize
values are no longer as representative of cipher strength as they once were.
I still need the cipher name, even if keysize is less important.
Before 3.0.0, cipher_info was directly accessible through
ssl.transform->cipher_ctx_enc.cipher_info
and SSL_CIPHER_USEKEYSIZE via
ssl.transform->cipher_ctx_enc.key_bitlen
With 3.0.0,
struct mbedtls_ssl_transform
is private in ssl_misc.h(and
transform
memberssl.MBEDTLS_PRIVATE(transform)
is private, too)With 3.0.0, how to get
cipher_info
andkey_bitlen
fromstruct mbedtls_ssl_context
?Here is a ridiculous chain for a simple lookup, and still not safe in 3.0.0:
and that still does not provide a way to access to mbedtls_cipher_context_t key_bitlen
How about:
Then, I can use
mbedtls_cipher_get_name()
for SSL_CIPHERmbedtls_cipher_get_key_bitlen()
for SSL_CIPHER_ALGKEYSIZEbut there is still no accessor to
ctx->MBEDTLS_PRIVATE(key_bitlen)
BTW,
mbedtls_cipher_get_key_bitlen()
shouldreturn (int) mbedtls_cipher_info_get_key_bitlen(ctx->MBEDTLS_PRIVATE(cipher_info));
rather than reaching through the structures directly
(
ctx->MBEDTLS_PRIVATE(cipher_info)->MBEDTLS_PRIVATE(key_bitlen)
)[edit: https://github.com/Add mbedtls_ssl_get_cipher_info() accessor #5417]
mbedtls_x509_name
member next_merged is now private(reasonable, since it is an implementation detail)
However, lighttpd mod_mbedtls.c
https_add_ssl_client_subject()
replaces theinefficient
mbedtls_x509_dn_gets()
which repeatedly callssnprintf()
(slow) forbuffer management.
https://git.lighttpd.net/lighttpd/lighttpd1.4/src/branch/master/src/mod_mbedtls.c#L2400
lighttpd formats components of client Subject DN into env vars SSL_CLIENT_S_DN_*.
NOTE: to properly walk a
mbedtls_x509_name
linked list,one needs to know if
nm->next
needs to be merged or not.[edit: https://github.com/Add access to
mbedtls_x509_name::next_merged
#5431]mbedtls_ssl_config_defaults
does not detect if called more than oncembedtls_ssl_config
paramsdhm_P
anddhm_G
are now private.lighttpd calls
mbedtls_mpi_free(ssl_ctx->MBEDTLS_PRIVATE(dhm_P));
mbedtls_mpi_free(ssl_ctx->MBEDTLS_PRIVATE(dhm_G));
before calling
mbedtls_ssl_config_defaults()
a second time when lighttpdreconfigures the config to use one of SUITEB* (e.g. SUITEB192)
Since
mbedtls_ssl_config_init()
zerosmbedtls_ssl_config
,calls to
mbedtls_ssl_config_defaults()
should probablymbedtls_mpi_free()
the
dhm_P
anddhm_G
params if they had previously been allocated.(This might be considered a bug, possibly resulting in a memory leak.)
[edit: Reset dhm_P and dhm_G if config call repeated; avoid memory leak #5353]
RFE: missing OCSP stapling support is a huge detriment to adoption of mbedTLS
on the server-side.
The text was updated successfully, but these errors were encountered: