mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
Update early data API for writing to unauthenticated clients
Change the early data API so that the server must use SSL_write_early_data() to write to an unauthenticated client. Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2737)
This commit is contained in:
parent
0665b4edae
commit
09f2887482
@ -34,7 +34,9 @@ These functions are used to send and recieve early data. Early data can be sent
|
||||
by the client immediately after its initial ClientHello without having to wait
|
||||
for the server to complete the handshake. Early data can only be sent if a
|
||||
session has previously been established with the server, and the server is known
|
||||
to support it.
|
||||
to support it. Additionally these functions can be used to send data from the
|
||||
server to the client when the client has not yet completed the authentication
|
||||
stage of the handshake.
|
||||
|
||||
Early data has weaker security properties than other data sent over an SSL/TLS
|
||||
connection. In particular the data is not forward secret and the server has no
|
||||
@ -51,10 +53,6 @@ unauthenticated at this point.
|
||||
A server or client can determine whether the full handshake has been completed
|
||||
or not by calling L<SSL_is_init_finished(3)>.
|
||||
|
||||
[[TODO(TLS1.3): The server uses SSL_write_ex()/SSL_write() to send data to an
|
||||
unauthenticated client. Should we create a separate function for this to avoid
|
||||
accidents??]]
|
||||
|
||||
On the client side the function SSL_SESSION_get_max_early_data() can be used to
|
||||
determine whether a session established with a server can be used to send early
|
||||
data. If the session cannot be used then this function will return 0. Otherwise
|
||||
@ -67,14 +65,15 @@ information on how to write bytes to the underlying connection, and how to
|
||||
handle any errors that may arise. This page will detail the differences between
|
||||
SSL_write_early_data() and L<SSL_write_ex(3)>.
|
||||
|
||||
SSL_write_early_data() must be the first IO function called on a new connection,
|
||||
i.e. it must occur before any calls to L<SSL_write_ex(3)>, L<SSL_read_ex(3)>,
|
||||
L<SSL_connect(3)>, L<SSL_do_handshake(3)> or other similar functions. It may be
|
||||
called multiple times to stream data to the server, but the total number of
|
||||
bytes written must not exceed the value returned from
|
||||
SSL_SESSION_get_max_early_data(). Once the initial SSL_write_early_data() call
|
||||
has completed successfully the client may interleave calls to L<SSL_read_ex(3)>
|
||||
and L<SSL_read(3)> with calls to SSL_write_early_data() as required.
|
||||
When called by a client, SSL_write_early_data() must be the first IO function
|
||||
called on a new connection, i.e. it must occur before any calls to
|
||||
L<SSL_write_ex(3)>, L<SSL_read_ex(3)>, L<SSL_connect(3)>, L<SSL_do_handshake(3)>
|
||||
or other similar functions. It may be called multiple times to stream data to
|
||||
the server, but the total number of bytes written must not exceed the value
|
||||
returned from SSL_SESSION_get_max_early_data(). Once the initial
|
||||
SSL_write_early_data() call has completed successfully the client may interleave
|
||||
calls to L<SSL_read_ex(3)> and L<SSL_read(3)> with calls to
|
||||
SSL_write_early_data() as required.
|
||||
|
||||
If SSL_write_early_data() fails you should call L<SSL_get_error(3)> to determine
|
||||
the correct course of action, as for L<SSL_write_ex(3)>.
|
||||
@ -85,8 +84,6 @@ L<SSL_do_handshake(3)>. Alternatively you can call a standard write function
|
||||
such as L<SSL_write_ex(3)>, which will transparently complete the connection and
|
||||
write the requested data.
|
||||
|
||||
Only clients may call SSL_write_early_data().
|
||||
|
||||
A server may choose to ignore early data that has been sent to it. Once the
|
||||
connection has been completed you can determine whether the server accepted or
|
||||
rejected the early data by calling SSL_get_early_data_status(). This will return
|
||||
@ -127,20 +124,26 @@ or if the early data was rejected.
|
||||
|
||||
=back
|
||||
|
||||
Once the initial SSL_read_early_data() call has completed successfully the
|
||||
server may interleave calls to L<SSL_write_ex(3)> and L<SSL_write(3)> with calls
|
||||
to SSL_read_early_data() as required. As noted above data sent via
|
||||
L<SSL_write_ex(3)> or L<SSL_write(3)> in this way is sent to an unauthenticated
|
||||
client.
|
||||
Once the initial SSL_read_early_data() call has completed successfully (i.e. it
|
||||
has returned SSL_READ_EARLY_DATA_SUCCESS or SSL_READ_EARLY_DATA_FINISH) then the
|
||||
server may choose to write data immediately to the unauthenticated client using
|
||||
SSL_write_early_data(). If SSL_read_early_data() returned
|
||||
SSL_READ_EARLY_DATA_FINISH then in some situations (e.g. if the client only
|
||||
support TLSv1.2) the handshake may have already been completed and calls
|
||||
to SSL_write_early_data() are not allowed. Call L<SSL_is_init_finished(3)> to
|
||||
determine whether the handshake has completed or not. If the handshake is still
|
||||
in progress then the server may interleave calls to SSL_write_early_data() with
|
||||
calls to SSL_read_early_data() as required.
|
||||
|
||||
Servers must not call L<SSL_read_ex(3)> or L<SSL_read(3)> until
|
||||
SSL_read_early_data() has returned with SSL_READ_EARLY_DATA_FINISH. Once it has
|
||||
done so the connection to the client still needs to be completed. Complete the
|
||||
connection by calling a function such as L<SSL_accept(3)> or
|
||||
L<SSL_do_handshake(3)>. Alternatively you can call a standard read function such
|
||||
as L<SSL_read_ex(3)>, which will transparently complete the connection and read
|
||||
the requested data. Note that it is an error to attempt to complete the
|
||||
connection before SSL_read_early_data() has returned SSL_READ_EARLY_DATA_FINISH.
|
||||
Servers must not call L<SSL_read_ex(3)>, L<SSL_read(3)>, L<SSL_write_ex(3)> or
|
||||
L<SSL_write(3)> until SSL_read_early_data() has returned with
|
||||
SSL_READ_EARLY_DATA_FINISH. Once it has done so the connection to the client
|
||||
still needs to be completed. Complete the connection by calling a function such
|
||||
as L<SSL_accept(3)> or L<SSL_do_handshake(3)>. Alternatively you can call a
|
||||
standard read function such as L<SSL_read_ex(3)>, which will transparently
|
||||
complete the connection and read the requested data. Note that it is an error to
|
||||
attempt to complete the connection before SSL_read_early_data() has returned
|
||||
SSL_READ_EARLY_DATA_FINISH.
|
||||
|
||||
Only servers may call SSL_read_early_data().
|
||||
|
||||
|
@ -1760,7 +1760,8 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
|
||||
if (!ssl_write_early_finish(s))
|
||||
return 0;
|
||||
} else if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
|
||||
|| s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
|
||||
|| s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY
|
||||
|| s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
|
||||
SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
@ -1820,17 +1821,14 @@ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (s->server) {
|
||||
SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (s->early_data_state) {
|
||||
case SSL_EARLY_DATA_NONE:
|
||||
if (!SSL_in_before(s)
|
||||
if (s->server
|
||||
|| !SSL_in_before(s)
|
||||
|| s->session == NULL
|
||||
|| s->session->ext.max_early_data == 0) {
|
||||
SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
SSLerr(SSL_F_SSL_WRITE_EARLY_DATA,
|
||||
ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
/* fall through */
|
||||
@ -1851,8 +1849,15 @@ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
|
||||
s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
|
||||
return ret;
|
||||
|
||||
case SSL_EARLY_DATA_READ_RETRY:
|
||||
/* We are a server writing to an unauthenticated client */
|
||||
s->early_data_state = SSL_EARLY_DATA_UNAUTH_WRITING;
|
||||
ret = SSL_write_ex(s, buf, num, written);
|
||||
s->early_data_state = SSL_EARLY_DATA_READ_RETRY;
|
||||
return ret;
|
||||
|
||||
default:
|
||||
SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
SSLerr(SSL_F_SSL_WRITE_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -621,6 +621,7 @@ typedef enum {
|
||||
SSL_EARLY_DATA_CONNECTING,
|
||||
SSL_EARLY_DATA_WRITE_RETRY,
|
||||
SSL_EARLY_DATA_WRITING,
|
||||
SSL_EARLY_DATA_UNAUTH_WRITING,
|
||||
SSL_EARLY_DATA_FINISHED_WRITING,
|
||||
SSL_EARLY_DATA_ACCEPT_RETRY,
|
||||
SSL_EARLY_DATA_ACCEPTING,
|
||||
|
@ -1624,10 +1624,10 @@ static int test_early_data_read_write(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Server should be able to write normal data, and client should be able to
|
||||
* Server should be able to write data, and client should be able to
|
||||
* read it.
|
||||
*/
|
||||
if (!SSL_write_ex(serverssl, MSG2, strlen(MSG2), &written)
|
||||
if (!SSL_write_early_data(serverssl, MSG2, strlen(MSG2), &written)
|
||||
|| written != strlen(MSG2)) {
|
||||
printf("Failed writing message 2\n");
|
||||
goto end;
|
||||
@ -1647,7 +1647,7 @@ static int test_early_data_read_write(void)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Server should still be able read early data after writing normal data */
|
||||
/* Server should still be able read early data after writing data */
|
||||
if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
|
||||
!= SSL_READ_EARLY_DATA_SUCCESS
|
||||
|| readbytes != strlen(MSG3)
|
||||
@ -1656,8 +1656,8 @@ static int test_early_data_read_write(void)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Write more normal data from server and read it from client */
|
||||
if (!SSL_write_ex(serverssl, MSG4, strlen(MSG4), &written)
|
||||
/* Write more data from server and read it from client */
|
||||
if (!SSL_write_early_data(serverssl, MSG4, strlen(MSG4), &written)
|
||||
|| written != strlen(MSG4)) {
|
||||
printf("Failed writing message 4\n");
|
||||
goto end;
|
||||
@ -1700,7 +1700,7 @@ static int test_early_data_read_write(void)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Client and server should not be able to write early data now */
|
||||
/* Client and server should not be able to write/read early data now */
|
||||
if (SSL_write_early_data(clientssl, MSG6, strlen(MSG6), &written)) {
|
||||
printf("Unexpected success writing early data\n");
|
||||
goto end;
|
||||
@ -1778,7 +1778,7 @@ static int test_early_data_read_write(void)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Client and server should not be able to write early data now */
|
||||
/* Client and server should not be able to write/read early data now */
|
||||
if (SSL_write_early_data(clientssl, MSG6, strlen(MSG6), &written)) {
|
||||
printf("Unexpected success writing early data (2)\n");
|
||||
goto end;
|
||||
|
Loading…
Reference in New Issue
Block a user