Re: TLS compatibility notes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On Jan 25, 2019, at 9:00 AM, Alan DeKok <aland@xxxxxxxxxxxxxxxxxxx> wrote:
> 
> On Jan 24, 2019, at 6:56 PM, Jouni Malinen <j@xxxxx> wrote:
>> 
>> On Thu, Jan 24, 2019 at 11:05:28AM -0500, Alan DeKok wrote:
>>> Hi, we're trying to get TLS 1.3 working with FreeRADIUS && wpa_supplicant.  As perhaps could be expected with any new standard, there are issues.
>> 
>> Which version of wpa_supplicant have you used for this? You'll need the
>> current snapshot of the master branch in hostap.git to the changes to
>> match draft-ietf-emu-eap-tls13-03.txt. Or well, I think I'm still
>> missing one of the changes (empty ApplData to indicate
>> server-TX-completion).
> 
>  IIRC, it was the current head.  Arran should know more.  He's on this list, so he can respond.

So there are two main issues with TLS based EAP methods, TLS 1.3 and OpenSSL.

- With EAP-TLS, hostapd master HEAD, OpenSSL 1.1.1a, and session tickets sent by the server after the handshake, OpenSSL seemed to fail with "TLS - SSL error: error:14231044:SSL routines:tls13_hkdf_expand:internal error".  This seems to be fixed with OpenSSL master and maybe the HEAD of their 1.1.1 release branch.

- With EAP-TTLS, hostapd master HEAD, OpenSSL master HEAD, authentication succeeds if no session tickets are sent, but fails if session tickets are sent by the server after the handshake.  Below is a detailed description of the issue.

With EAP-TTLS, authentication fails where a session ticket is sent by the server after the TLS handshake completes.

Following the call flow on the client (wpa_supplicant) side:

eap_ttls.c line 1423 uses the absence of pending data from the server as an indicator that it should start phase2.  Previously this worked as no data would be sent after the handshake, but with TLS 1.3 and session tickets enabled, at this point in the code, wpa_supplicant will see that there's pending (session ticket) data from the server, not call eap_ttls_phase2_start, and call eap_peer_tls_decrypt instead.

eap_peer_tls_decrypt attempts to reassemble record data, then calls tls_connection_decrypt which calls SSL_read().

SSL_read()* correctly processes the session ticket data, but returns -1, as there's no pending application_data.  Calling SSL_get_error() returns SSL_WANT_READ, as SSL_read() wants more input records to return application_data.

tls_connection_decrypt doesn't check the reason for the error, as I believe there's the assumption is should be receiving complete application_data records, so any error is bad.  We see a "Decryption failed - SSL_read" error with all the fields set to zero, and the failure propagates up the call stack.  Authentication then fails.

I think the check at eap_ttls.c - eap_ttls_decrypt line 1423 is incorrect and likely always has been.  Looking at RFC 5281 section 7.6 "Determining Whether to Enter Phase2"

  The client always has the first opportunity to initiate phase 2 upon
   completion of phase 1.  If the client has no AVPs to send, it either
   sends an Acknowledgement if the TTLS server sends
   the final phase 1 message, or simply does not piggyback a phase 2
   message when it issues the final phase 1 message (as will occur
   during session resumption).
   If the client does not initiate phase 2, the TTLS server, at its
   option, may either complete the EAP-TTLS negotiation without entering
   phase 2 or initiate phase 2 by tunneling AVPs to the client.


My interpretation of this, is that the server must wait to see if the client initiates phase 2 or not, *before* sending any application data.  If TLS records from the server are pending processing at the point where the client is making a decision about whether to enter phase2, it should process those records, and if application_data is present, it should error out.

eap_peer_tls_decrypt and functions lower in the call stack should be changed so that they should only indicate a failure if there's an actual failure.  application_data not being available is not in of itself an error condition.  In fact the *presence* of application_data in some cases may be considered to be an error condition depending on the phase 2 state.  The decision about what to do about the presence or absence of application data should be made higher in the call stack in eap_ttls_decrypt.

eap_ttls_decrypt should be changed so that:

- if (data->phase2_start)
  - if in_data && wbabuf_len(in_data) > 0.  
    eap_peer_tls_decrypt should be called to process the data.
    - if eap_peer_tls_decrypt returns a failure indication then eap_ttls_decrypt should return a failure indication.
    - if eap_peer_tls_decrypt indicates it processed application_data, then eap_ttls_decrypt should return a failure indication.
    - if eap_peer_tls_decrypt indicates it processed non-application data, then eap_ttls_phase_start() should be called.
  - else eap_ttls_phase2_start() should be called - this is the TLS <= 1.2 or the no new_session_ticket case.

How eap_peer_tls_decrypt determines exactly what happened is slightly more complex, but simply distinguishing between failure, application_data processed, or handshake messages processed, is relatively simple.

Note: With OpenSSL 1.1.1 SSL_MODE_AUTO_RETRY is on by default, prior to 1.1.1 it was off by default.  SSL_MODE_AUTO_RETRY basically causes SSL_read() to process any non-application_data that's pending and return -1 if no application data was processed.   The below assumes SSL_MODE_AUTO_RETRY is left enabled.

a) if SSL_read() < 0 && SSL_get_error != SSL_WANT_READ - An actual error condition has occurred.
b) if SSL_read() < 0 && SSL_get_error == SSL_WANT_READ - Non-application_data was processed.
c) if SSL_read() > 0 - application_data was processed.

I can put a patch set together to handle the OpenSSL crypto library if that helps, or the above in unclear.

>>> The largest issues seem to be in OpenSSL.  The git HEAD seems to work better than the released versions, which don't really work well at all.
>> 
>> I have managed to get EAP-TLS working with TLS v1.3 between hostapd EAP
>> server and wpa_supplicant EAP peer while using unmodified OpenSSL 1.1.1.
> 
>  We haven't tried that.  But here's one bug found by Arran:
> 
> https://github.com/openssl/openssl/issues/8077

Yeah this is a fun one and was why I found the issues dealing with session tickets.  Basically even if you've set SSL_SESS_CACHE_OFF (to disable stateful tickets), and SSL_OP_NO_TICKET (to disable stateless tickets), if TLS 1.3 is negotiated, OpenSSL will still send two stateless tickets after the handshake.

You need to call SSL_CTX_set_num_tickets(ctx, 0) to actually disable them.  Additionally, In the case of EAP-TLS, EAP-TTLS, EAP-PEAP and other TLS based EAP methods as only one ticket is required, EAP server implementations should call SSL_CTX_set_num_tickets(ctx, 1).

>>> Previously, the session tickets were sent before the "server finished" message, before the handshake was finished.  They now appear after that, but before the application data.
>> 
>> Yes and that's something that did require changes in
>> hostapd/wpa_supplicant for the earlier version of the draft. I think my
>> comments on that area resulted in the latest draft using an explicit
>> notification to allow that area to be simplified, but I did not yet
>> finish that implementation (it was a bit difficult to extract knowledge
>> of the exact state and get OpenSSL to behave on both server and client
>> side).

If the above fix isn't sufficient, the msg_callback (SSL_set_msg_callback(SSL *, cb)), can be used to determine what messages were processed during the last call to SSL_read().  I think this is probably the most reliable way of inferring what's going on.

>> I did get this working with older EAP-TLS v1.3 draft design. TLS v1.3
>> support is disabled by default in wpa_supplicant for now, but with
>> phase1="tls_disable_v1_3=0" in the network profile, this still works at
>> least against the hostapd EAP server implementation. And this does
>> include successful exchange of session tickets.

Yes, EAP-TLS works fine with session tickets (as tested against FreeRADIUS master HEAD), it is EAP-TTLS and EAP-PEAP that do not.  Basically anything with a 'phase 2' fails if a session ticket is sent after the handshake.

>> I don't think I did anything for this part yet or even tested this
>> match. The only automated test case that I currently have for EAP-TLS
>> with TLSv1.3 seems to be using RSA certs on both ends.
> 
>  We're adding a large test matrix on the FreeRADIUS side which should help.
> 
>  But this issue should be also seen with TLS 1.2, because the issue is cipher negotiation, not TLS versions.
> 
>  If you set cipher_suite to something that *doesn't* match the certificates, OpenSSL won't notice until such time as it has to exchange the certs.  And it will then fail.
> 
>  I think this was never noticed because versions that supported newer cert methods would always negotiation those methods.  It's only with the advent of ECC certs that OpenSSL will negotiate *both* ECC and RSA, even if it doesn't have RSA certs available.  This naturally confuses the other end, who might want just RSA.

I think we should deal with this in a separate thread.

-Arran

*  I tried calling SSL_do_handshake() as an alternative to SSL_read() but it does not trigger processing session ticket data in this case, as internally OpenSSL believes the handshake is complete.
_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux