Mbed TLS is now part of TrustedFirmware.org.

What is the correct way to use session tickets?


May 8, 2017 13:52
Daniel Egger

Hi,

with OpenSSL it is possible to simply take the session ticket after the handshake and store it somewhere and load it back before attempting a new session; if the ticket is not valid for the endpoint or rejected for some reason the OpenSSL will simply resume with a regular handshake.

Now mbedTLS seemingly does not like this approach: when loading back a session which is not suitable for the server the handshake will abort with MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; if I then naively try to reset the session and start over I'll receive MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE.

So I am wondering what the correct way of resuming a session is, hopefully without major stunts...

 
May 8, 2017 15:46
Ron Eldor

Hi Daniel,
There is not enough information to understand reason for these errors. I assume you are compiling your mbed TLS stack with MBEDTLS_SSL_SESSION_TICKETS defined.
For more hints, I suggest you look at ssl_client2 example to understand how mbed TLS client works with session tickets, and verify you have all the correct ssl configuration parameters.
Regards,
mbed TLS Team member
Ron

 
May 8, 2017 18:09
Daniel Egger

Yes, I've a full server grade build here. Session tickets also work just fine if you're connecting just a single connection to a single server.

However my application needs multiple connections to multiple servers in parallel. One of them typically online for many hours or days while another one is connecting periodically every few minutes for about 30s max. However the connection mechanism for those is the same, they can't be distinguished and parameters may change any time. The problem here really seems to be that there're no fallback to a regular handshake when supplying incorrect or outdated session information. I'd also be happy to use the session cache but that again is only available for server use, not client...

 
May 11, 2017 13:18
Daniel Egger

So is there a sane and safe way to attempt a TLS session resumption and fall back to a full handshake if resumption was not possible or a way to figure out that resumption will fail without completely destroying a set-up connection and completely starting over?

 
May 11, 2017 14:51
Ron Eldor

Hi Daniel,
According to RFC5077:

If the server cannot or does not want to honor the ticket, then it can initiate a full handshake with the client.

If the session you are sending is outdated or invalid, then the server should ignore the session ticket and initiate a full handshake. If the server fails, there might be something different causing the failure.
Does the server try to renegotiate?
Regards,
mbed TLS Team member
Ron

 
May 11, 2017 19:09
Daniel Egger

With OpenSSL it works just against the very same server. I'm not quite sure how to verify that but if you point me into the right direction I'd be happy to collect and provide that information.

 
May 14, 2017 07:44
Ron Eldor

Hi Daniel,
mbed TLS is supposed to do a full handshake resumption, without any change from your side. It is most probable that it is a matter of configuring your client.
To check if the server is trying to do a renegotiation, check if after a successful handshake, or after the client sends the message with the session ticket id, the server sends a ServerHello message.
I would check how you configure your mbed TLS client: what is defined in config.h and what you define in your ssl config. I would also check if the server is sending a FATAL ALERT message before disconnecting.
Regards,
mbed TLS Team member
Ron

 
May 15, 2017 08:01
Ron Eldor

Hi Daniel, I would like to correct my writer's error before. For renegotiation, the server sends a HelloRequest message, not a ServerHello.
Regards,
mbed TLS Team member
Ron

 
May 15, 2017 08:30
Daniel Egger

Hi Ron,

this is what I get on the client side:

  mbedTLS: 0x7fb459c0b098: dumping 'server hello, version' (2 bytes)
  mbedTLS: 0x7fb459c0b098: 0000:  03 01                                            ..
  mbedTLS: 0x7fb459c0b098: server hello, current time: 1494833442
  mbedTLS: 0x7fb459c0b098: dumping 'server hello, random bytes' (32 bytes)
  mbedTLS: 0x7fb459c0b098: 0000:  59 19 59 22 ba c2 4c 4f 51 a4 9d 75 cf c5 58 75  Y.Y"..LOQ..u..Xu
  mbedTLS: 0x7fb459c0b098: 0010:  82 3b 88 26 66 89 76 ee de 3a 28 16 b7 64 6c e1  .;.&f.v..:(..dl.
  mbedTLS: 0x7fb459c0b098: server hello, session id len.: 32
  mbedTLS: 0x7fb459c0b098: dumping 'server hello, session id' (32 bytes)
  mbedTLS: 0x7fb459c0b098: 0000:  36 21 a3 7e 1f e5 f1 e2 c5 e8 ae f9 cd 0b 6b c1  6!.~..........k.
  mbedTLS: 0x7fb459c0b098: 0010:  9c 73 50 cc 06 29 e4 6c 05 6d 52 af 5b c7 89 99  .sP..).l.mR.[...
  mbedTLS: 0x7fb459c0b098: no session has been resumed
  mbedTLS: 0x7fb459c0b098: server hello, chosen ciphersuite: 0039
  mbedTLS: 0x7fb459c0b098: server hello, compress alg.: 0
  mbedTLS: 0x7fb459c0b098: server hello, chosen ciphersuite: TLS-DHE-RSA-WITH-AES-256-CBC-SHA
  mbedTLS: 0x7fb459c0b098: server hello, total extension length: 5
  mbedTLS: 0x7fb459c0b098: found renegotiation extension
  mbedTLS: 0x7fb459c0b098: <= parse server hello
  mbedTLS: 0x7fb459c0b098: client state: 3
  mbedTLS: 0x7fb459c0b098: => flush output
  mbedTLS: 0x7fb459c0b098: <= flush output
  mbedTLS: 0x7fb459c0b098: => parse certificate
  mbedTLS: 0x7fb459c0b098: => read record
  mbedTLS: 0x7fb459c0b098: => fetch input
  mbedTLS: 0x7fb459c0b098: in_left: 0, nb_want: 5
  mbedTLS: 0x7fb459c0b098: in_left: 0, nb_want: 5
  mbedTLS: 0x7fb459c0b098: ssl->f_recv(_timeout)() returned 5 (-0xfffffffb)
  mbedTLS: 0x7fb459c0b098: <= fetch input
  mbedTLS: 0x7fb459c0b098: input record: msgtype = 20, version = [3:1], msglen = 1
  mbedTLS: 0x7fb459c0b098: => fetch input
  mbedTLS: 0x7fb459c0b098: in_left: 5, nb_want: 6
  mbedTLS: 0x7fb459c0b098: in_left: 5, nb_want: 6
  mbedTLS: 0x7fb459c0b098: ssl->f_recv(_timeout)() returned 1 (-0xffffffff)
  mbedTLS: 0x7fb459c0b098: <= fetch input
  mbedTLS: 0x7fb459c0b098: <= read record
  mbedTLS: 0x7fb459c0b098: bad certificate message
  mbedTLS: 0x7fb459c0b098: <= handshake

The configuration is the default configuration with #define MBEDTLS_THREADING_C and #define MBEDTLS_THREADING_PTHREAD added.

This is what the server says:

[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write change cipher spec A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write finished A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 flush data
[Mon May 15 09:30:43 2017] [debug] ssl_engine_io.c(1893): OpenSSL: I/O error, 5 bytes expected to read on BIO#7f400913d0c0 [mem: 7f4009143be0]
[Mon May 15 09:30:43 2017] [debug] ssl_engine_kernel.c(1903): OpenSSL: Exit: error in SSLv3 read finished A
[Mon May 15 09:30:43 2017] [debug] ssl_engine_kernel.c(1903): OpenSSL: Exit: error in SSLv3 read finished A
[Mon May 15 09:30:43 2017] [info] [client 122.147.240.11] (70014)End of file found: SSL handshake interrupted by system [Hint: Stop button pressed in browser?!]
[Mon May 15 09:30:43 2017] [info] [client 122.147.240.11] Connection closed to child 5 with abortive shutdown
 
May 15, 2017 13:32
Ron Eldor

Hi Daniel,
According to the server log, it seems that the server accepts the session sent by the client.
You can see in the server log that after it receives the ClientHello, it sends a ServerHello, and then sends a ChangeCipherSpec and sends a finish message.
I believe the cause for failure is because the client thinks that the session is not resumed, and expects a certificate.
You can see in the client log: no session has been resumed
I beleive this is caused in the following if statement:

if( ssl->handshake->resume == 0 || n == 0 ||
#if defined(MBEDTLS_SSL_RENEGOTIATION)
        ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ||
#endif
        ssl->session_negotiate->ciphersuite != i ||
        ssl->session_negotiate->compression != comp ||
        ssl->session_negotiate->id_len != n ||
        memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 )

Please check that in your client you call mbedtls_ssl_set_session with the saved session, as in the ssl_client2 example, and verify it is on the correct ssl context, and that the context doesn't get overridden on your multithreaded environment.
In addition, try configuring your client with mbedtls_ssl_conf_renegotiation( &ssl, MBEDTLS_SSL_RENEGOTIATION_ENABLED ), as I see the server has added a renegotiation extension.
I hope this helps
Regards,
mbed TLS Team member
Ron

 
May 16, 2017 01:51
Daniel Egger

Hi Ron,

I believe the cause for failure is because the client thinks that the session is not resumed, and expects a certificate.

Yes and this is correct. As I explained earlier the session cannot be resumed because it is invalid and thus has to be renegotiated.

verify it is on the correct ssl context,

No, it is a different SSL context. Which brings me back to my question how to figure this out before actually attempting attempting to resume an invalid session if mbedTLS is not capable of renegotiating in that situation as there are a multitude of reasons why a session might be invalid and thus (IMNSHO) there should be a way to fall back to a regular negotiation instead of failing.

In addition, try configuring your client with mbedtls_ssl_conf_renegotiation( &ssl, MBEDTLS_SSL_RENEGOTIATION_ENABLED ), as I see the server has added a renegotiation extension.

That didn't help.

 
May 16, 2017 07:28
Ron Eldor

Hi Daniel,

As I explained earlier the session cannot be resumed because it is invalid and thus has to be renegotiated.

Why do you think the session is invalid? As I mentioned before, according to the logs, the server recognizes the session ticket, and sends a ChangeCipherSpec message.

No, it is a different SSL context.

If it is a different ssl context, then this explains why you fail, and why the client thinks that the server didn't accept the ticket. If you are using a different ssl context, you shouldn't resume, and shouldn't try to resume a session ticket, unless you call mbedtls_ssl_set_session before resuming the session ticket. mbed TLS knows how to fall back to regular negotiation, if everything is configured correct.
As mentioned, the reason for failure is that the server actually resumes the session, but the client doesn't know it is resumed, because it is not configured correct, and thus there is a mismatch in the state machine. ( Client expects the server Certificate message, while the server actually sends the ChangeCipherSpec message )
Regards,
mbed TLS Team member
Ron

 
May 16, 2017 08:40
Daniel Egger

Hi Ron,

Why do you think the session is invalid?

Because the session was was established with a different server before. It would be rather scary if it wasn't invalid.

If it is a different ssl context, then this explains why you fail, and why the client thinks that the server didn't accept the ticket.

I know for a fact that the session I'm trying to resume is not valid and that the server alerts the client to that. However that is nothing I can't control since there's no way (known to me) to figure out whether a session can be resumed without sending it to the server. Now, when I do the exact same thing with OpenSSL (i.e. sending an invalid session ticket), OpenSSL gracefully obeys and does a full regular handshake, mbedTLS instead fails the whole connection.

If you are using a different ssl context, you shouldn't resume, and shouldn't try to resume a session ticket, unless you call mbedtls_ssl_set_session before resuming the session ticket.

Sorry, I can't parse that. I am calling mbedtls_ssl_set_session -- that's exactly what causes the problem; without it works fine but does not resume sessions which is a complete performance disaster for my use case.

mbed TLS knows how to fall back to regular negotiation, if everything is configured correct. As mentioned, the reason for failure is that the server actually resumes the session, but the client doesn't know it is resumed, because it is not configured correct, and thus there is a mismatch in the state machine. (Client expects the server Certificate message, while the server actually sends the ChangeCipherSpec message)

Okay, I looked back at the server logs caused by the OpenSSL version and you're right:

[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write certificate A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1274): [client 61.219.219.140] handing out temporary 1024 bit DH key
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write key exchange A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server done A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 flush data

So how would I apply the session correctly, currently I'm doing something like this:

    if ((ret = mbedtls_ssl_set_session (&connctx->ssl, &_crypto_ctx->saved_session)) != 0)
    {
        /* error handling here */
    }

    while ((ret = mbedtls_ssl_handshake (&connctx->ssl)) != 0)
    {
        /* error handling here */
    }
 
May 16, 2017 13:37
Ron Eldor

Hi Daniel,

It would be rather scary if it wasn't invalid.

From the server logs when working with open ssl, it shows that either the server doesn't accept the ticket sent by the client, or the client doesn't support session tickets. I would check if the OPEN SSL client sends a session ticket extension or not.
This is because after the server is sending the ServerHello message, it sends the Server certificate, and so on. From the server log when working with the mbed TLS client, it seems that the server does accept the session, because after sending the ServerHello message, it sends the ChangeCipherSpec message, instead of the certificate. This indicates that the server has all the information it needs for the session. If you are positive that the session wasn't negotiated with this server, then perhaps there is something wrong with the id, and the server accepts this session, as it has it stored, for some reason. Please check the id and compare it other previous sessions connected to this server. It is strange why the server accepts this session.
I have a question, why not store saved_session in connctx instead of _crypto_ctx ? This way, the save_session will be bound to the specific ssl context.
Regards,
mbed TLS Team member
Ron

 
May 17, 2017 03:03
Daniel Egger

From the server logs when working with open ssl, it shows that either the server doesn't accept the ticket sent by the client, or the client doesn't support session tickets. I would check if the OPEN SSL client sends a session ticket extension or not.

Hm, maybe I just picked the wrong block of log messages but probably the server doesn't explicitly mention that it is actually resuming a session but it can be seen by the lack of certificate exchange; it certainly does use reuse sessions if allowed by the configuration.

The code checks for the SSL_OP_NO_TICKET ticket option and based upon that we set a previously retrieved session ticket. Also there's a SSL_session_reused () function we're using to indicate whether a session was resumed or not and that one indicates that the feature works as expected.

If you are positive that the session wasn't negotiated with this server, then perhaps there is something wrong with the id, and the server accepts this session, as it has it stored, for some reason.

I am certain of that. The first session is a short term HTTPS, the second is persistent XMPP with a different server, and after that many HTTPS connections again, HTTPS is all the same target for this test. After XMPP the HTTPS connections will not establish anymore, as a workaround I could probably reset the stored session when the connection handshake fails so upon retry it might work again.

If you are positive that the session wasn't negotiated with this server, then perhaps there is something wrong with the id, and the server accepts this session, as it has it stored, for some reason. Please check the id and compare it other previous sessions connected to this server.

It gets even stranger. So now I'm tracking the id of the session and I was all the time wondering why the second session does not fail. Turns out the reason for that is that the client receives and parses the ticket but even after calling mbedtls_ssl_get_session(&connctx->ssl, &_crypto_ctx->saved_session) on a established connection (i.e. handshake finished), the &_crypto_ctx->saved_session.id is still zeroed out. Only after the second session it will actually pick up an id and the id stays the same. When does that get updated?

I have a question, why not store saved_session in connctx instead of _crypto_ctx ? This way, the save_session will be bound to the specific ssl context.

connctx only exists for the duration of a single connection, _crypto_ctx is shared between all connections for the entirety of the application runtime. Storing the session in connctx would be rather pointless as it would only be used in the rare circumstance that a connection gets dropped during communication.

 
May 17, 2017 14:12
Ron Eldor

Hi Daniel,

Hm, maybe I just picked the wrong block of log messages but probably the server doesn't explicitly mention that it is actually resuming a session but it can be seen by the lack of certificate exchange; it certainly does use reuse sessions if allowed by the configuration

Well. my answers are according to the logs I see. According to the server logs, it doesn't say when it resumes, but according to its state machine logs, I can tell when there is a resume, and when there isn't.
server logs with mbed TLS client:

[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write change cipher spec A
[Mon May 15 09:30:42 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write finished A

As you can see, no certificate is sent, so the server accepts the session
server logs with the open ssl Client:

[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write certificate A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1274): [client 61.219.219.140] handing out temporary 1024 bit DH key
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write key exchange A
[Tue May 16 10:14:57 2017] [debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server done A

As you can see, the server is sending the certifiate, so it doesn't accept the session ticket.

The first session is a short term HTTPS, the second is persistent XMPP with a different server, and after that many HTTPS connections again

How about when working with the temporary HTTPS server, don't use a session ticket? How will this affect your performance?

as a workaround I could probably reset the stored session when the connection handshake fails so upon retry it might work again.

Yes, you should try that

When does that get updated?

As you can see from the code, the session id is updated in the following cases:
* In mbedtls_ssl_set_session , the session id from the stored session is copied to the negotiation session.
* In ssl_write_client_hello in case there is a already an allocated session ticket. * In ssl_parse_server_hello in th following conditions:

   if( ssl->handshake->resume == 0 || n == 0 ||
#if defined(MBEDTLS_SSL_RENEGOTIATION)
        ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ||
#endif
        ssl->session_negotiate->ciphersuite != i ||
        ssl->session_negotiate->compression != comp ||
        ssl->session_negotiate->id_len != n ||
        memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 )

I suggest you follow the logs from the first ClientHello message, until the failure, on both client and server, and see what is the id that the client sends, and what is the id that the server sends, and if the server sends a certificate or not
I hope this gives you some hints
Regards,
mbed TLS Team member
Ron

 
May 17, 2017 15:05
Daniel Egger

Hi Ron,

How about when working with the temporary HTTPS server, don't use a session ticket?

There is no temporary HTTPS server. This is generic networking code which is used for any kind of connection the software opens; this may end like in my lab example I'm using to reproduce the problem but it may be completely different as well, and most likely will be as this example is rather artificial. Since the code is truly generic there's no telling which connection is used for which purpose, and even if I knew the purpose of the connection there's still a chance that one takes longer than anticipated and others end up much shorter than anticipated. If it doesn't even work for my contrived example there's no way I can assume it would work in the real world...

How will this affect your performance?

What you're asking for is not possible. Either it works correctly and out-of-the-box or I simply cannot use it at all. For some specific purposes (high frequency connections of hundred thousands or even millions of devices) mbedTLS simply cannot be used because session resumption using tickets is a must have so the load balancers on the market actually have a chance of handling the load; the performance requirements for a full handshake are at least 2 magnitudes(!) higher than the requirements needed for resuming and keeping established sessions.

I suggest you follow the logs from the first ClientHello message, until the failure, on both client and server, and see what is the id that the client sends, and what is the id that the server sends, and if the server sends a certificate or not

I did. Yet after the handshake of the first connection the session->id remains at its initialisation value. This does not look correct at all...

I'm rather surprised than even doing the same with OpenSSL, despite it's shitty or even non-existing documentation, was a lot more straight forward to implement and worked right away.

 
May 18, 2017 12:54
Ron Eldor

Hi Daniel,
Note also that the session id is discarded, once the client receives a ticket from the server, according to RFC 5077 section 3.4.
As I mentioned, mbed TLS should work out of the box for session resumption, and we would like to get to the bottom of this.
According to the client logs of the failed case I have the following analysis:

mbedTLS: 0x7fb459c0b098: no session has been resumed

This means that one of the following statements is true:

if( ssl->handshake->resume == 0 || n == 0 ||
#if defined(MBEDTLS_SSL_RENEGOTIATION)
        ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ||
#endif
        ssl->session_negotiate->ciphersuite != i ||
        ssl->session_negotiate->compression != comp ||
        ssl->session_negotiate->id_len != n ||
        memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 )

and then the client expects for the next TLS handshake message, which is the server certificate. In case all the statements are false, then the client changes to expected state of Change Cipher Suite.
I suggest you check which one of these statements return true.
Later in the log, there is the failure:

 mbedTLS: 0x7fb459c0b098: input record: msgtype = 20, version = [3:1], msglen = 1
  mbedTLS: 0x7fb459c0b098: => fetch input
  mbedTLS: 0x7fb459c0b098: in_left: 5, nb_want: 6
  mbedTLS: 0x7fb459c0b098: in_left: 5, nb_want: 6
  mbedTLS: 0x7fb459c0b098: ssl->f_recv(_timeout)() returned 1 (-0xffffffff)
  mbedTLS: 0x7fb459c0b098: <= fetch input
  mbedTLS: 0x7fb459c0b098: <= read record
  mbedTLS: 0x7fb459c0b098: bad certificate message
  mbedTLS: 0x7fb459c0b098: <= handshake

bad certificate message is printed in several locations, within the function 'mbedtls_ssl_parse_certificate' , first one being: if( ssl->in_msgtype != if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )). The msg Type received is 20, which is ChangeCipherSpec, instead of the expected 22, which is MBEDTLS_SSL_MSG_HANDSHAKE, so this is why the failure. This means that the server sent the ChangeCipherSpec message after it sent the ServerHello message, which means that it accepted the session ticket.
Please verify that you are calling mbedtls_ssl_session_reset before calling mbedtls_ssl_set_session, as perhaps the ssl context you are using is not initialized, and then ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE is true.
Regards,
mbed TLS Team member
Ron

 
May 22, 2017 09:06
Daniel Egger

I suggest you check which one of these statements return true.

This one is tripping (157 vs 57): ssl->session_negotiate->ciphersuite != i ||

Please verify that you are calling mbedtls_ssl_session_reset before calling mbedtls_ssl_set_session,

Tried that, no change.

 
May 22, 2017 14:50
Ron Eldor

Hi Daniel,

This one is tripping (157 vs 57): ssl->session_negotiate->ciphersuite != i ||

This means that the cipher id sent in the ServerHello message (TLS-DHE-RSA-WITH-AES-256-CBC-SHA) is different then the cipher suite that the client has in the ticket sent. (TLS-RSA-WITH-AES-256-GCM-SHA384)
It is strange why the server accepts this session ticket.
I assume you are using on both server an Apache server. I have noticed in The Apcahe documentation that you can configure a secret key for encrypting and decrypting the session ticket. Please verify you are not using same key on both servers.
I have also noticed in the server logs that it is SSLv3. Is the other server using SSLv3 as well?
It is important to understand the session what happens to the session in between handshakes, before you call mbedtls_ssl_set_session.

Tried that, no change.

You should do regardless if there wasn't a change. the session should be reset before handshake.
Regards,
mbed TLS Team member
Ron

 
May 22, 2017 20:34
Daniel Egger

I assume you are using on both server an Apache server.

Negative, one is Apache, the other prosody -- a XMPP server. Different machines, different hostnames but the certificate is the same wildcard certificate.

SSLv3 should be disabled. Not sure why the debug logs mention SSLv3 but the final information message says: Protocol: TLSv1, Cipher: DHE-RSA-AES256-SHA (256/256 bits)

You should do regardless if there wasn't a change. the session should be reset before handshake.

Okay, will keep that.

 
May 25, 2017 14:22
Ron Eldor

Hi Daniel,
We would really want to get to the bottom of this. It is very strange why the server accepts the session ticket, although it shouldn't. We see from the logs that the session ticket the client sends and the server accepts, is different than the session that later the client checks when receiving the ServerHello message.
Please follow the session, specifically if it changes between one handshake, and then the new ctls handshake with the second server.
Please check whether the key that encrypts the session ticket on the two servers is same, for some reason.
It would be helpful to follow the full logs starting from the first handshake, up to the failure.
Regards,
mbed TLS Team member
Ron