PSK with TLSv1.3

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

PSK with TLSv1.3

Johannes Bauer-2
Hi list,

I'm in the process of refactoring/updating code that has been using
TLS-PSK with TLSv1.2 for a number of years successfully. I want to
upgrade it so that it uses TLSv1.3 exclusively.

I find it *exceptionally* hard to wrap my head around the new API and
the documentation/manpages are extremely confusing to me.

E.g., while
https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_psk_use_session_callback.html
mentions specifically TLSv1.3 clients, there's no mention of server
implementation and the text does not seem to have been updated for
TLSv1.3 entirely (e.g., there's mention of "the callback" -- clearly
previously there was only one, now there's two,
SSL_psk_use_session_cb_func and SSL_psk_client_cb_func).

I'm struggling with all of it, in particular the way the server callback
works in TLSv1.3: What I'm doing now is register a

static int psk_server_callback(SSL *ssl, const unsigned char *identity,
size_t identity_len, SSL_SESSION **sessptr);

using

SSL_CTX_set_psk_find_session_callback(cctx, psk_server_callback);

Then, inside the callback I create a SSL_SESSION* in the callback (if I
want to return a PSK) using SSL_SESSION_new(). Setting the master key
(that's the PSK, right?) using SSL_SESSION_set1_master_key and the
protocol version using SSL_SESSION_set_protocol_version is straightforward.

But what the heck am I supposed to do with SSL_SESSION_set_cipher? The
text in
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_psk_find_session_callback.html
does not contain any hint on what to do in the server case and the text
provided in the client manpage is exceedingly confusing:

"Only the handshake digest associated with the ciphersuite is relevant
for the PSK (the server may go on to negotiate any ciphersuite which is
compatible with the digest). The application can use any TLSv1.3
ciphersuite."

So, wait, I can use any TLSv1.3 ciphersuite but it's not relevant
because only the MD of the suite is used, everything else is discarded?
So I return a cipher suite value, but it doesn't have to do anything
with the cipher suites that I allow, it's just a "wrapper" for a MD?

Here's what I'm doing right now in my server callback:

static int psk_server_callback(SSL *ssl, const unsigned char *identity,
size_t identity_len, SSL_SESSION **sessptr) {
        fprintf(stderr, "PSK server SSL %p identity %s len %ld sess %p\n", ssl,
identity, identity_len, *sessptr);
        SSL_SESSION *sess = SSL_SESSION_new();
        SSL_SESSION_set1_master_key(sess, (const unsigned char*)"\x00\x11\x22", 3);
        SSL_SESSION_set_cipher(sess, SSL_get_pending_cipher(ssl));
        SSL_SESSION_set_protocol_version(sess, TLS1_3_VERSION);
        *sessptr = sess;
        return 1;
}

All error checking omitted for now, this is obviously just a sample.
When I try to connect to my server on the command line using s_client:

$ openssl s_client -connect 127.0.0.1:12345 -psk_identity foo -psk 001122

The server pukes:

PSK server SSL 0x623000000100 identity foo len 3 sess (nil)
139933268309760:error:141F906E:SSL routines:tls_parse_ctos_psk:bad
extension:../ssl/statem/extensions_srvr.c:1267:

And I have no idea what that's supposed to mean.

I'm willing to update the documentation/manpage and create a PR, but I
don't understand it as-it right now. So any help getting me up to speed
would be greatly appreciated. Examples would be also extremely useful
for this.

All the best,
Johannes
Reply | Threaded
Open this post in threaded view
|

Re: PSK with TLSv1.3

Johannes Bauer-2
On 23.10.19 11:24, Johannes Bauer wrote:

> All error checking omitted for now, this is obviously just a sample.
> When I try to connect to my server on the command line using s_client:
>
> $ openssl s_client -connect 127.0.0.1:12345 -psk_identity foo -psk 001122
>
> The server pukes:
>
> PSK server SSL 0x623000000100 identity foo len 3 sess (nil)
> 139933268309760:error:141F906E:SSL routines:tls_parse_ctos_psk:bad
> extension:../ssl/statem/extensions_srvr.c:1267:
>
> And I have no idea what that's supposed to mean.

One step further... I've peeked at s_server.c and copied some of that
code. I.e., concretely I now am at:

const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
const SSL_CIPHER *cipher = SSL_CIPHER_find(ssl, tls13_aes128gcmsha256_id);
if (!cipher) {
        return 0;
}
SSL_SESSION_set_cipher(sess, cipher);

But, uhm... this is positively terrifying code. Is this how it's
supposed to look, i.e., hard-coded magic numbers in the application?! Or
is that just the route s_server took and there's a preferred, better way?

In any case, while it throws a different error message now, it still
does not work:

PSK server SSL 0x62300000fd00 identity foo len 3 sess (nil)
140710464452352:error:14201076:SSL routines:tls_choose_sigalg:no
suitable signature algorithm:../ssl/t1_lib.c:2649:

I've never in the setup limited the signature algorithms and s_client
does not, either (when I peek at the ClientHello it advertises a whole
bunch of signature algorithms).

Any advice?
Thank you,
Johannes
Reply | Threaded
Open this post in threaded view
|

Re: PSK with TLSv1.3

Matt Caswell-2
In reply to this post by Johannes Bauer-2


On 23/10/2019 10:24, Johannes Bauer wrote:
> Hi list,
>
> I'm in the process of refactoring/updating code that has been using
> TLS-PSK with TLSv1.2 for a number of years successfully. I want to
> upgrade it so that it uses TLSv1.3 exclusively.
>
> I find it *exceptionally* hard to wrap my head around the new API and
> the documentation/manpages are extremely confusing to me.

I'd be grateful if you could submit suggested improvements as PRs to
make this clearer for the next person who comes along trying to do this.


>
> E.g., while
> https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_psk_use_session_callback.html
> mentions specifically TLSv1.3 clients, there's no mention of server
> implementation

The page you referenced is the man page for clients. The man page for
servers is here:

https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_psk_find_session_callback.html

Unfortunately this page is not made any clearer by a copy & paste error
in the opening paragraph which suggests it is about the client side API
calls rather than the server side one. I've just opened a PR to fix that
here:

https://github.com/openssl/openssl/pull/10245


> and the text does not seem to have been updated for
> TLSv1.3 entirely (e.g., there's mention of "the callback" -- clearly
> previously there was only one, now there's two,
> SSL_psk_use_session_cb_func and SSL_psk_client_cb_func).
>
> I'm struggling with all of it, in particular the way the server callback
> works in TLSv1.3: What I'm doing now is register a
>
> static int psk_server_callback(SSL *ssl, const unsigned char *identity,
> size_t identity_len, SSL_SESSION **sessptr);
>
> using
>
> SSL_CTX_set_psk_find_session_callback(cctx, psk_server_callback);
>
> Then, inside the callback I create a SSL_SESSION* in the callback (if I
> want to return a PSK) using SSL_SESSION_new(). Setting the master key
> (that's the PSK, right?) using SSL_SESSION_set1_master_key and the
> protocol version using SSL_SESSION_set_protocol_version is straightforward.
>
> But what the heck am I supposed to do with SSL_SESSION_set_cipher? The
> text in
> https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_psk_find_session_callback.html
> does not contain any hint on what to do in the server case and the text
> provided in the client manpage is exceedingly confusing:
>
> "Only the handshake digest associated with the ciphersuite is relevant
> for the PSK (the server may go on to negotiate any ciphersuite which is
> compatible with the digest). The application can use any TLSv1.3
> ciphersuite."
>
> So, wait, I can use any TLSv1.3 ciphersuite but it's not relevant
> because only the MD of the suite is used, everything else is discarded?
> So I return a cipher suite value, but it doesn't have to do anything
> with the cipher suites that I allow, it's just a "wrapper" for a MD?

Yes, exactly that. This comes about because of some quirks in the
TLSv1.3 spec. Historically (TLSv1.2 and below) the ciphersuite that is
negotiated is an important part of the session (SSL_SESSION object) and
the same ciphersuite is used in any subsequent resumption of that
session. In TLSv1.3 there is no difference between a PSK and a session.
The mechanism used for establishing a connection using a PSK is exactly
the same one used for resuming a session. So when we establish an
initial connection in TLSv1.3 we store away various values in the
session in exactly the same way that we do for TLSv1.2, and then use
some of them in the resumption. In the case of the ciphersuite its
actually only the MD part that we're interested in. With a PSK of course
there was no "initial handshake", so there was no previous ciphersuite
negotiated. However, since the mechanism is the same as for a resumption
we still need to have one there so we can get the MD out of it - which
leads to this slightly surprising way of doing things.


>
> Here's what I'm doing right now in my server callback:
>
> static int psk_server_callback(SSL *ssl, const unsigned char *identity,
> size_t identity_len, SSL_SESSION **sessptr) {
> fprintf(stderr, "PSK server SSL %p identity %s len %ld sess %p\n", ssl,
> identity, identity_len, *sessptr);
> SSL_SESSION *sess = SSL_SESSION_new();
> SSL_SESSION_set1_master_key(sess, (const unsigned char*)"\x00\x11\x22", 3);
> SSL_SESSION_set_cipher(sess, SSL_get_pending_cipher(ssl));
> SSL_SESSION_set_protocol_version(sess, TLS1_3_VERSION);
> *sessptr = sess;
> return 1;
> }
>
> All error checking omitted for now, this is obviously just a sample.
> When I try to connect to my server on the command line using s_client:
>
> $ openssl s_client -connect 127.0.0.1:12345 -psk_identity foo -psk 001122
>
> The server pukes:
>
> PSK server SSL 0x623000000100 identity foo len 3 sess (nil)
> 139933268309760:error:141F906E:SSL routines:tls_parse_ctos_psk:bad
> extension:../ssl/statem/extensions_srvr.c:1267:

That error is coming from this sanity check:

    if (PACKET_remaining(&binder) != hashsize) {
        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
                 SSL_R_BAD_EXTENSION);
        goto err;
    }

We could do with updating the error code to be something more helpful
(PRs welcome!). "Bad extension" doesn't really tell you anything. The
problem is that the callback has found the SESSION object for the
presented identity but the hash size used by the client doesn't match
the hash size associated with the ciphersuite in the SESSION object.

Matt

Reply | Threaded
Open this post in threaded view
|

Re: PSK with TLSv1.3

Matt Caswell-2
In reply to this post by Johannes Bauer-2


On 23/10/2019 12:32, Johannes Bauer wrote:

> One step further... I've peeked at s_server.c and copied some of that
> code. I.e., concretely I now am at:
>
> const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
> const SSL_CIPHER *cipher = SSL_CIPHER_find(ssl, tls13_aes128gcmsha256_id);
> if (!cipher) {
> return 0;
> }
> SSL_SESSION_set_cipher(sess, cipher);
>
> But, uhm... this is positively terrifying code. Is this how it's
> supposed to look, i.e., hard-coded magic numbers in the application?! Or
> is that just the route s_server took and there's a preferred, better way?

Unfortunately the only way we have for getting hold of a single
SSL_CIPHER object is to use the SSL_CIPHER_find() function. You can also
get the list of ciphers configured for a particular SSL object or
SSL_CTX....but you that's an even worse way of getting hold of a single
SSL_CIPHER. It would be nice to have a function to get hold of an
SSL_CIPHER based on its name and a function to get hold of one based on
its id as defined in the tls1.h, e.g. TLS1_3_CK_AES_256_GCM_SHA384 - but
at the moment such a function doesn't exist.


>
> In any case, while it throws a different error message now, it still
> does not work:
>
> PSK server SSL 0x62300000fd00 identity foo len 3 sess (nil)
> 140710464452352:error:14201076:SSL routines:tls_choose_sigalg:no
> suitable signature algorithm:../ssl/t1_lib.c:2649:
>
> I've never in the setup limited the signature algorithms and s_client
> does not, either (when I peek at the ClientHello it advertises a whole
> bunch of signature algorithms).

Since you're using PSKs I'm guessing you haven't set up a certificate.
If no suitable PSK has been found then OpenSSL will press ahead and
attempt to do an "initial" handshake with a certificate. It gets so far
and attempts to find a signature algorithm to use that is in the list of
signature algorithms presented by the client, as well as in the list of
signature algorithms configured for the server, and *also* is suitable
for use with one of the certificates configured for use by the server.
If there are no certificates configured then there is no signature
algorithm that can match these criteria, and you will get this error
message.

Matt