[openssl-commits] [openssl] master update
Matt Caswell
matt at openssl.org
Thu Mar 2 17:48:46 UTC 2017
The branch master has been updated
via 83750d9b2b51bb622138d48fc82eb408b64d8057 (commit)
via cd9f7f624ee434606b084d77e6845f15f8c501bc (commit)
via 09f288748266577cc38b77ca31c47b9e9f15890e (commit)
via 0665b4edae3fec740ebe12fe2946d4cc9585ca86 (commit)
via f533fbd44a36daac9cc304ff648782e366391b00 (commit)
via ef466accdc196fe796301a06cdc6e94cb315ae9b (commit)
via ade1e88806461df5516525a8f36e707820167e01 (commit)
via 3eaa4170956dc7ca2a0c9fc9414dc42cac7b426e (commit)
via 5f9820380ff82fc07e93e430b97da516997d3771 (commit)
via f7e393be4725c33739d46a58de94a06ebdc6e49d (commit)
via d7f8783ff9e88ad34e010564d721a55a48c6d674 (commit)
via 564547e482406c2d4c56a59e288b3a479dac2d74 (commit)
via 4004ce5f6cd6540a07d6d1a4cef7138821d5e596 (commit)
via bc908c679b0d13ed5fdeb06d4c2eda8b0b5f5ce6 (commit)
via 6437b802f19fb022da88f59cb3071ebdcd2838f6 (commit)
via 0a5ece5bd20aac050d3c77c4f1fb760aa7892ab0 (commit)
via fd6c102520e3829a10fb273eaa62bbccf793e22b (commit)
via f5b519c416ad70f0bc0e9a5750be1367224eee5a (commit)
via 46dcb9457edc1bcf224a36f9d559363507440fd7 (commit)
via fcc4757823a00ed21cd0b5fd90122eb4f249a10c (commit)
via 7daf7156d8fb10e8ec18d806b653d425707c2c0d (commit)
via f637004037a11bc04682f54571e3ff11d48d8e36 (commit)
via a832b5ef7a6080a6a66d1135c80c9aaf5570fc02 (commit)
via 38df5a452777b612f75796531c0b2629da6aa550 (commit)
via 538bea6c8184670a8d1608ef288a4e1813dcefa6 (commit)
via 329114f91f1a560bcf25ff2ebf5d608079e82272 (commit)
via 2c604cb9af4a879ea43fd7fd84883a5e97ab0fe0 (commit)
via 6746648c4270442fefc05ae25b0afcf326391b60 (commit)
via bfa9a9afe82e603339801da73ddbabd02d919888 (commit)
via 70ef40a05e06d055a89c6c8f9309f047e7e834f1 (commit)
via 67f78eadd00ce1c3a5bbde5e42530c1a61d363a2 (commit)
via 10109364bf0f07c393bd4283470f1bf57f31cecb (commit)
via c117af6765928f3fc61585b01f5d722162914d80 (commit)
via 576eb3958cbb18484680c0bbe7cbf2dce9af0f1b (commit)
via b2cc7f313ec1c8386ace3b351457c33af8861ce2 (commit)
via e0655186f9c520a7f3c15643081649f841c221ae (commit)
via fe5e20fd267bae655c37ba8d67d74c0db566e088 (commit)
via 1ea4d09a3c049cd3b0748410e0c53b98082980cb (commit)
via d781d247d1ef9331983f456d616659108c857d0d (commit)
via 6cb422654de11eb13f50b36d7d59e65fec029229 (commit)
via d49e23ec589e32e70f485fac379417097a831897 (commit)
via 923ac8271b35eda36eb8fd9d8909671aee3ca022 (commit)
via 0a87d0ac628685a1b420851f1614829a952cda5f (commit)
via a4f376af7e98161c7513614cf4a110724a5a65f5 (commit)
via 49e7fe12eac1e84af726e0110ee29073699ed46b (commit)
via 5d5b3fba1fc15e3a63876aa9c8deae351369781b (commit)
via 29fac541b0af22fa1874c5594fabeff754c7dafe (commit)
via 048b189336e5703f19e695245ae656513d5f2797 (commit)
via 3fc8d856105e4716d3121348996ea3c61e7e4b7d (commit)
from 73fb82b72c7544cf52d95ac29d4a45b253395715 (commit)
- Log -----------------------------------------------------------------
commit 83750d9b2b51bb622138d48fc82eb408b64d8057
Author: Matt Caswell <matt at openssl.org>
Date: Thu Mar 2 17:40:43 2017 +0000
More early data documentation updates following feedback
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit cd9f7f624ee434606b084d77e6845f15f8c501bc
Author: Matt Caswell <matt at openssl.org>
Date: Thu Mar 2 16:05:02 2017 +0000
Update the API documentation for the latest early data changes
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 09f288748266577cc38b77ca31c47b9e9f15890e
Author: Matt Caswell <matt at openssl.org>
Date: Thu Mar 2 15:49:33 2017 +0000
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 at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 0665b4edae3fec740ebe12fe2946d4cc9585ca86
Author: Matt Caswell <matt at openssl.org>
Date: Thu Mar 2 15:05:36 2017 +0000
Rename SSL_write_early() to SSL_write_early_data()
This is for consistency with the rest of the API where all the functions
are called *early_data*.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit f533fbd44a36daac9cc304ff648782e366391b00
Author: Matt Caswell <matt at openssl.org>
Date: Thu Mar 2 14:42:55 2017 +0000
Rename SSL_read_early() to SSL_read_early_data()
This is for consistency with the rest of the API where all the functions
are called *early_data*.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit ef466accdc196fe796301a06cdc6e94cb315ae9b
Author: Matt Caswell <matt at openssl.org>
Date: Tue Feb 28 00:40:24 2017 +0000
Updates to the early data documentation
Following on from the latest API changes.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit ade1e88806461df5516525a8f36e707820167e01
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 27 20:55:04 2017 +0000
Updates to s_server and s_client for the latest early_data API changes
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 3eaa4170956dc7ca2a0c9fc9414dc42cac7b426e
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 27 20:54:39 2017 +0000
Make SSL_write_early_finish() an internal only function
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 5f9820380ff82fc07e93e430b97da516997d3771
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 27 11:20:22 2017 +0000
Add early_data tests
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit f7e393be4725c33739d46a58de94a06ebdc6e49d
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 27 11:19:57 2017 +0000
Various fixes required to allow SSL_write/SSL_read during early data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit d7f8783ff9e88ad34e010564d721a55a48c6d674
Author: Matt Caswell <matt at openssl.org>
Date: Sat Feb 25 15:59:44 2017 +0000
Enable the server to call SSL_write() without stopping the ability to call SSL_read_early()
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 564547e482406c2d4c56a59e288b3a479dac2d74
Author: Matt Caswell <matt at openssl.org>
Date: Sat Feb 25 15:34:07 2017 +0000
Enable the client to call SSL_read() without stopping the ability to call SSL_write_early()
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 4004ce5f6cd6540a07d6d1a4cef7138821d5e596
Author: Matt Caswell <matt at openssl.org>
Date: Sat Feb 25 00:06:49 2017 +0000
Introduce a new early_data state in the state machine
Also simplifies the state machine a bit.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit bc908c679b0d13ed5fdeb06d4c2eda8b0b5f5ce6
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 17:08:41 2017 +0000
Improve the early data sanity check in SSL_do_handshake()
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 6437b802f19fb022da88f59cb3071ebdcd2838f6
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 16:17:00 2017 +0000
Add documentation for the new s_client and s_server early_data options
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 0a5ece5bd20aac050d3c77c4f1fb760aa7892ab0
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 16:11:03 2017 +0000
Tighten sanity checks when calling early data functions
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit fd6c102520e3829a10fb273eaa62bbccf793e22b
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 15:38:38 2017 +0000
Add documentation for the early data functions
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit f5b519c416ad70f0bc0e9a5750be1367224eee5a
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 14:17:41 2017 +0000
Make SSL_get_early_data_status() take a const
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 46dcb9457edc1bcf224a36f9d559363507440fd7
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 14:08:59 2017 +0000
Make SSL_get_max_early_data() and SSL_CTX_get_max_early_data() take a const
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit fcc4757823a00ed21cd0b5fd90122eb4f249a10c
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 14:08:06 2017 +0000
Add a SSL_SESSION_get_max_early_data() function
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 7daf7156d8fb10e8ec18d806b653d425707c2c0d
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 13:51:04 2017 +0000
Don't attempt to write more early_data than we know the server will accept
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit f637004037a11bc04682f54571e3ff11d48d8e36
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 12:45:37 2017 +0000
Only accept early_data if the negotiated ALPN is the same
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit a832b5ef7a6080a6a66d1135c80c9aaf5570fc02
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 11:40:49 2017 +0000
Skip early_data if appropriate after a HelloRetryRequest
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 38df5a452777b612f75796531c0b2629da6aa550
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 11:13:25 2017 +0000
Don't accept early_data if we are going to issue a HelloRetryRequest
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 538bea6c8184670a8d1608ef288a4e1813dcefa6
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 10:29:20 2017 +0000
Add extra validation parsing the server-to-client early_data extension
Check that we actually resumed the session, and that we selected the first
identity.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 329114f91f1a560bcf25ff2ebf5d608079e82272
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 09:34:32 2017 +0000
Remove some TLSv1.3 TODOs that are no longer relevant
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 2c604cb9af4a879ea43fd7fd84883a5e97ab0fe0
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 24 09:30:54 2017 +0000
Validate the ticket age for resumed sessions
If the ticket age calcualtions do not check out then we must not accept
early data (it could be a replay).
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 6746648c4270442fefc05ae25b0afcf326391b60
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 16:54:11 2017 +0000
Ensure the max_early_data option to s_server can be 0
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit bfa9a9afe82e603339801da73ddbabd02d919888
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 16:41:15 2017 +0000
Provide a default value for max_early_data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 70ef40a05e06d055a89c6c8f9309f047e7e834f1
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 14:29:36 2017 +0000
Check max_early_data against the amount of early data we actually receive
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 67f78eadd00ce1c3a5bbde5e42530c1a61d363a2
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 16:05:57 2017 +0000
Make sure we reset the read sequence when skipping records
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 10109364bf0f07c393bd4283470f1bf57f31cecb
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 12:36:35 2017 +0000
Disallow handshake messages in the middle of early_data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit c117af6765928f3fc61585b01f5d722162914d80
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 12:25:21 2017 +0000
Fix seg fault when sending early_data using CCM ciphersuites
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 576eb3958cbb18484680c0bbe7cbf2dce9af0f1b
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 11:52:43 2017 +0000
Get s_client to report on whether early data was accepted or not
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit b2cc7f313ec1c8386ace3b351457c33af8861ce2
Author: Matt Caswell <matt at openssl.org>
Date: Thu Feb 23 11:53:12 2017 +0000
Implement client side parsing of the early_data extension
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit e0655186f9c520a7f3c15643081649f841c221ae
Author: Matt Caswell <matt at openssl.org>
Date: Wed Feb 22 15:24:11 2017 +0000
Add a "-early_data" option to s_server
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit fe5e20fd267bae655c37ba8d67d74c0db566e088
Author: Matt Caswell <matt at openssl.org>
Date: Wed Feb 22 14:09:42 2017 +0000
Fix changing of the cipher state when dealing with early data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 1ea4d09a3c049cd3b0748410e0c53b98082980cb
Author: Matt Caswell <matt at openssl.org>
Date: Wed Feb 22 13:01:48 2017 +0000
Construct the server side early_data extension
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit d781d247d1ef9331983f456d616659108c857d0d
Author: Matt Caswell <matt at openssl.org>
Date: Tue Feb 21 17:14:42 2017 +0000
Provide an SSL_read_early() function for reading early data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 6cb422654de11eb13f50b36d7d59e65fec029229
Author: Matt Caswell <matt at openssl.org>
Date: Tue Feb 21 16:40:16 2017 +0000
Change the cipher state when sending early data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit d49e23ec589e32e70f485fac379417097a831897
Author: Matt Caswell <matt at openssl.org>
Date: Tue Feb 21 16:39:43 2017 +0000
Implement the early data changes required in tls13_change_cipher_state()
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 923ac8271b35eda36eb8fd9d8909671aee3ca022
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 20 16:00:20 2017 +0000
Add an option to s_client to send early_data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 0a87d0ac628685a1b420851f1614829a952cda5f
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 20 16:35:03 2017 +0000
Parse the early_data extension
We also skip any early_data that subsequently gets sent. Later commits will
process it if we can.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit a4f376af7e98161c7513614cf4a110724a5a65f5
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 20 15:44:42 2017 +0000
Construct the early_data extension
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 49e7fe12eac1e84af726e0110ee29073699ed46b
Author: Matt Caswell <matt at openssl.org>
Date: Tue Feb 21 09:22:22 2017 +0000
Provide functions to write early data
We provide SSL_write_early() which *must* be called first on a connection
(prior to any other IO function including SSL_connect()/SSL_do_handshake()).
Also SSL_write_early_finish() which signals the end of early data.
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 5d5b3fba1fc15e3a63876aa9c8deae351369781b
Author: Matt Caswell <matt at openssl.org>
Date: Mon Feb 20 14:56:51 2017 +0000
Parse the ticket_early_data_info extension
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 29fac541b0af22fa1874c5594fabeff754c7dafe
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 17 17:41:46 2017 +0000
Teach SSL_trace() about the early_data_info extension
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 048b189336e5703f19e695245ae656513d5f2797
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 17 17:01:16 2017 +0000
Add a -max_early_data option to s_server
Allows you to set the number of bytes that can be sent as early data
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
commit 3fc8d856105e4716d3121348996ea3c61e7e4b7d
Author: Matt Caswell <matt at openssl.org>
Date: Fri Feb 17 16:52:12 2017 +0000
Construct the ticket_early_data_info extension
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
-----------------------------------------------------------------------
Summary of changes:
apps/s_client.c | 59 +++-
apps/s_server.c | 87 +++++-
doc/man1/s_client.pod | 10 +-
doc/man1/s_server.pod | 13 +
doc/man3/SSL_read_early_data.pod | 216 +++++++++++++
include/openssl/ssl.h | 37 ++-
include/openssl/ssl3.h | 13 +-
include/openssl/tls1.h | 3 +
ssl/record/rec_layer_s3.c | 48 ++-
ssl/record/record_locl.h | 1 +
ssl/record/ssl3_record.c | 85 ++++-
ssl/record/ssl3_record_tls13.c | 20 +-
ssl/s3_msg.c | 5 +-
ssl/ssl_asn1.c | 28 +-
ssl/ssl_err.c | 16 +
ssl/ssl_lib.c | 212 +++++++++++++
ssl/ssl_locl.h | 76 ++++-
ssl/ssl_sess.c | 6 +
ssl/statem/extensions.c | 43 +++
ssl/statem/extensions_clnt.c | 68 ++++
ssl/statem/extensions_srvr.c | 79 ++++-
ssl/statem/statem.c | 57 +++-
ssl/statem/statem.h | 3 +
ssl/statem/statem_clnt.c | 81 ++++-
ssl/statem/statem_lib.c | 24 ++
ssl/statem/statem_locl.h | 16 +
ssl/statem/statem_srvr.c | 79 +++--
ssl/t1_enc.c | 8 +-
ssl/t1_trce.c | 14 +-
ssl/tls13_enc.c | 124 ++++++--
test/sslapitest.c | 655 +++++++++++++++++++++++++++++++++++++++
test/tls13secretstest.c | 9 +-
util/libssl.num | 8 +
33 files changed, 2084 insertions(+), 119 deletions(-)
create mode 100644 doc/man3/SSL_read_early_data.pod
diff --git a/apps/s_client.c b/apps/s_client.c
index 351b5b9..b48c306 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -547,7 +547,7 @@ typedef enum OPTION_choice {
OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME,
OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST,
OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF,
- OPT_KEYLOG_FILE,
+ OPT_KEYLOG_FILE, OPT_EARLY_DATA,
OPT_V_ENUM,
OPT_X_ENUM,
OPT_S_ENUM,
@@ -732,6 +732,7 @@ const OPTIONS s_client_options[] = {
{"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"},
#endif
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
+ {"early_data", OPT_EARLY_DATA, '<', "File to send as early data"},
{NULL, OPT_EOF, 0x00, NULL}
};
@@ -895,7 +896,7 @@ int s_client_main(int argc, char **argv)
int c_status_req = 0;
#endif
BIO *bio_c_msg = NULL;
- const char *keylog_file = NULL;
+ const char *keylog_file = NULL, *early_data_file = NULL;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
@@ -1371,6 +1372,9 @@ int s_client_main(int argc, char **argv)
case OPT_KEYLOG_FILE:
keylog_file = opt_arg();
break;
+ case OPT_EARLY_DATA:
+ early_data_file = opt_arg();
+ break;
}
}
if (count4or6 >= 2) {
@@ -2355,6 +2359,40 @@ int s_client_main(int argc, char **argv)
break;
}
+ if (early_data_file != NULL
+ && SSL_get0_session(con) != NULL
+ && SSL_SESSION_get_max_early_data(SSL_get0_session(con)) > 0) {
+ BIO *edfile = BIO_new_file(early_data_file, "r");
+ size_t readbytes, writtenbytes;
+ int finish = 0;
+
+ if (edfile == NULL) {
+ BIO_printf(bio_err, "Cannot open early data file\n");
+ goto shut;
+ }
+
+ while (!finish) {
+ if (!BIO_read_ex(edfile, cbuf, BUFSIZZ, &readbytes))
+ finish = 1;
+
+ while (!SSL_write_early_data(con, cbuf, readbytes, &writtenbytes)) {
+ switch (SSL_get_error(con, 0)) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_ASYNC:
+ case SSL_ERROR_WANT_READ:
+ /* Just keep trying - busy waiting */
+ continue;
+ default:
+ BIO_printf(bio_err, "Error writing early data\n");
+ BIO_free(edfile);
+ goto shut;
+ }
+ }
+ }
+
+ BIO_free(edfile);
+ }
+
for (;;) {
FD_ZERO(&readfds);
FD_ZERO(&writefds);
@@ -2940,6 +2978,23 @@ static void print_stuff(BIO *bio, SSL *s, int full)
}
#endif
+ if (SSL_version(s) == TLS1_3_VERSION) {
+ switch (SSL_get_early_data_status(s)) {
+ case SSL_EARLY_DATA_NOT_SENT:
+ BIO_printf(bio, "Early data was not sent\n");
+ break;
+
+ case SSL_EARLY_DATA_REJECTED:
+ BIO_printf(bio, "Early data was rejected\n");
+ break;
+
+ case SSL_EARLY_DATA_ACCEPTED:
+ BIO_printf(bio, "Early data was accepted\n");
+ break;
+
+ }
+ }
+
SSL_SESSION_print(bio, SSL_get_session(s));
if (SSL_get_session(s) != NULL && keymatexportlabel != NULL) {
BIO_printf(bio, "Keying material exporter:\n");
diff --git a/apps/s_server.c b/apps/s_server.c
index 6d35cb8..3190eab 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -104,6 +104,7 @@ static void free_sessions(void);
#ifndef OPENSSL_NO_DH
static DH *load_dh_param(const char *dhfile);
#endif
+static void print_connection_info(SSL *con);
/* static int load_CA(SSL_CTX *ctx, char *file);*/
@@ -147,6 +148,8 @@ static int dtlslisten = 0;
static char *psk_identity = "Client_identity";
char *psk_key = NULL; /* by default PSK is not used */
+int early_data = 0;
+
static unsigned int psk_server_cb(SSL *ssl, const char *identity,
unsigned char *psk,
unsigned int max_psk_len)
@@ -719,7 +722,7 @@ typedef enum OPTION_choice {
OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
- OPT_KEYLOG_FILE,
+ OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_EARLY_DATA,
OPT_S_ENUM,
OPT_V_ENUM,
OPT_X_ENUM
@@ -916,6 +919,9 @@ const OPTIONS s_server_options[] = {
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
#endif
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
+ {"max_early_data", OPT_MAX_EARLY, 'n',
+ "The maximum number of bytes of early data"},
+ {"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"},
{NULL, OPT_EOF, 0, NULL}
};
@@ -992,6 +998,7 @@ int s_server_main(int argc, char *argv[])
unsigned int split_send_fragment = 0, max_pipelines = 0;
const char *s_serverinfo_file = NULL;
const char *keylog_file = NULL;
+ int max_early_data = -1;
/* Init of few remaining global variables */
local_argc = argc;
@@ -1500,7 +1507,16 @@ int s_server_main(int argc, char *argv[])
case OPT_KEYLOG_FILE:
keylog_file = opt_arg();
break;
-
+ case OPT_MAX_EARLY:
+ max_early_data = atoi(opt_arg());
+ if (max_early_data < 0) {
+ BIO_printf(bio_err, "Invalid value for max_early_data\n");
+ goto end;
+ }
+ break;
+ case OPT_EARLY_DATA:
+ early_data = 1;
+ break;
}
}
argc = opt_num_rest();
@@ -1991,6 +2007,9 @@ int s_server_main(int argc, char *argv[])
if (set_keylog_file(ctx, keylog_file))
goto end;
+ if (max_early_data >= 0)
+ SSL_CTX_set_max_early_data(ctx, max_early_data);
+
BIO_printf(bio_s_out, "ACCEPT\n");
(void)BIO_flush(bio_s_out);
if (rev)
@@ -2191,6 +2210,45 @@ static int sv_body(int s, int stype, unsigned char *context)
SSL_set_tlsext_debug_arg(con, bio_s_out);
}
+ if (early_data) {
+ int write_header = 1, edret = SSL_READ_EARLY_DATA_ERROR;
+ size_t readbytes;
+
+ while (edret != SSL_READ_EARLY_DATA_FINISH) {
+ for (;;) {
+ edret = SSL_read_early_data(con, buf, bufsize, &readbytes);
+ if (edret != SSL_READ_EARLY_DATA_ERROR)
+ break;
+
+ switch (SSL_get_error(con, 0)) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_ASYNC:
+ case SSL_ERROR_WANT_READ:
+ /* Just keep trying - busy waiting */
+ continue;
+ default:
+ BIO_printf(bio_err, "Error reading early data\n");
+ ERR_print_errors(bio_err);
+ goto err;
+ }
+ }
+ if (readbytes > 0) {
+ if (write_header) {
+ BIO_printf(bio_s_out, "Early data received:\n");
+ write_header = 0;
+ }
+ raw_write_stdout(buf, (unsigned int)readbytes);
+ (void)BIO_flush(bio_s_out);
+ }
+ }
+ if (write_header)
+ BIO_printf(bio_s_out, "No early data received\n");
+ else
+ BIO_printf(bio_s_out, "\nEnd of early data\n");
+ if (SSL_is_init_finished(con))
+ print_connection_info(con);
+ }
+
if (fileno_stdin() > s)
width = fileno_stdin() + 1;
else
@@ -2516,15 +2574,7 @@ static void close_accept_socket(void)
static int init_ssl_connection(SSL *con)
{
int i;
- const char *str;
- X509 *peer;
long verify_err;
- char buf[BUFSIZ];
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
- const unsigned char *next_proto_neg;
- unsigned next_proto_neg_len;
-#endif
- unsigned char *exportedkeymat;
int retry = 0;
#ifndef OPENSSL_NO_DTLS
@@ -2618,6 +2668,22 @@ static int init_ssl_connection(SSL *con)
return (0);
}
+ print_connection_info(con);
+ return 1;
+}
+
+static void print_connection_info(SSL *con)
+{
+ const char *str;
+ X509 *peer;
+ char buf[BUFSIZ];
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+ const unsigned char *next_proto_neg;
+ unsigned next_proto_neg_len;
+#endif
+ unsigned char *exportedkeymat;
+ int i;
+
if (s_brief)
print_ssl_summary(con);
@@ -2688,7 +2754,6 @@ static int init_ssl_connection(SSL *con)
}
(void)BIO_flush(bio_s_out);
- return (1);
}
#ifndef OPENSSL_NO_DH
diff --git a/doc/man1/s_client.pod b/doc/man1/s_client.pod
index 0c9329d..bbb86c2 100644
--- a/doc/man1/s_client.pod
+++ b/doc/man1/s_client.pod
@@ -105,6 +105,8 @@ B<openssl> B<s_client>
[B<-nextprotoneg protocols>]
[B<-ct|noct>]
[B<-ctlogfile>]
+[B<-keylogfile file>]
+[B<-early_data file>]
=head1 DESCRIPTION
@@ -528,11 +530,17 @@ for SCTs.
A file containing a list of known Certificate Transparency logs. See
L<SSL_CTX_set_ctlog_list_file(3)> for the expected file format.
-=item B<-keylogfile path>
+=item B<-keylogfile file>
Appends TLS secrets to the specified keylog file such that external programs
(like Wireshark) can decrypt TLS connections.
+=item B<-early_data file>
+
+Reads the contents of the specified file and attempts to send it as early data
+to the server. This will only work with resumed sessions that support early
+data and when the server accepts the early data.
+
=back
=head1 CONNECTED COMMANDS
diff --git a/doc/man1/s_server.pod b/doc/man1/s_server.pod
index 94289e8..c16b562 100644
--- a/doc/man1/s_server.pod
+++ b/doc/man1/s_server.pod
@@ -113,6 +113,8 @@ B<openssl> B<s_server>
[B<-status_file file>]
[B<-alpn protocols>]
[B<-nextprotoneg protocols>]
+[B<-max_early_data>]
+[B<-early_data>]
=head1 DESCRIPTION
@@ -527,6 +529,17 @@ The list should contain most wanted protocols first.
Protocol names are printable ASCII strings, for example "http/1.1" or
"spdy/3".
+=item B<-max_early_data arg>
+
+Change the default maximum early data bytes that are specified for new sessions
+and any incoming early data (when used in conjunction with the B<-early_data>
+flag). The default value is approximately 16k. The argument must be an integer
+greater than or equal to 0.
+
+=item B<-early_data>
+
+Accept early data where possible.
+
=back
=head1 CONNECTED COMMANDS
diff --git a/doc/man3/SSL_read_early_data.pod b/doc/man3/SSL_read_early_data.pod
new file mode 100644
index 0000000..4567de7
--- /dev/null
+++ b/doc/man3/SSL_read_early_data.pod
@@ -0,0 +1,216 @@
+=pod
+
+=head1 NAME
+
+SSL_set_max_early_data,
+SSL_CTX_set_max_early_data,
+SSL_get_max_early_data,
+SSL_CTX_get_max_early_data,
+SSL_SESSION_get_max_early_data,
+SSL_write_early_data,
+SSL_read_early_data,
+SSL_get_early_data_status
+- functions for sending and receiving early data
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data);
+ uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx);
+ int SSL_set_max_early_data(SSL *s, uint32_t max_early_data);
+ uint32_t SSL_get_max_early_data(const SSL_CTX *s);
+ uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s);
+
+ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written);
+
+ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes);
+
+ int SSL_get_early_data_status(const SSL *s);
+
+=head1 DESCRIPTION
+
+These functions are used to send and recieve early data where TLSv1.3 has been
+negotiated. 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. 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 does not have forward secrecy and there are
+no guarantees that the same early data was not replayed across multiple
+connections. For this reason extreme care should be exercised when using early
+data. For specific details, consult the TLS 1.3 specification.
+
+When a server receives early data it may opt to immediately respond by sending
+application data back to the client. Data sent by the server at this stage is
+done before the full handshake has been completed. Specifically the client's
+authentication messages have not yet been received, i.e. the client is
+unauthenticated at this point and care should be taken when using this
+capability.
+
+A server or client can determine whether the full handshake has been completed
+or not by calling L<SSL_is_init_finished(3)>.
+
+On the client side, the function SSL_SESSION_get_max_early_data() can be used to
+determine if 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 it
+will return the maximum number of early data bytes that can be sent.
+
+A client uses the function SSL_write_early_data() to send early data. This
+function is similar to the L<SSL_write_ex(3)> function, but with the following
+differences. See L<SSL_write_ex(3)> for information on how to write bytes to
+the underlying connection, and how to handle any errors that may arise. This
+page describes the differences between SSL_write_early_data() and
+L<SSL_write_ex(3)>.
+
+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)>.
+
+When the client no longer wishes to send any more early data then it should
+complete the handshake by calling a function such as L<SSL_connect(3)> or
+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.
+
+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
+SSL_EARLY_DATA_ACCEPTED if the data was accepted, SSL_EARLY_DATA_REJECTED if it
+was rejected or SSL_EARLY_DATA_NOT_SENT if no early data was sent. This function
+may be called by either the client or the server.
+
+A server uses the SSL_read_early_data() function to receive early data on a
+connection. As for SSL_write_early_data() this must be the first IO function
+called on a connection, i.e. it must occur before any calls to
+L<SSL_write_ex(3)>, L<SSL_read_ex(3)>, L<SSL_accept(3)>, L<SSL_do_handshake(3)>,
+or other similar functions.
+
+SSL_read_early_data() is similar to L<SSL_read_ex(3)> with the following
+differences. Refer to L<SSL_read_ex(3)> for full details.
+
+SSL_read_early_data() may return 3 possible values:
+
+=over 4
+
+=item SSL_READ_EARLY_DATA_ERROR
+
+This indicates an IO or some other error occured. This should be treated in the
+same way as a 0 return value from L<SSL_read_ex(3)>.
+
+=item SSL_READ_EARLY_DATA_SUCCESS
+
+This indicates that early data was successfully read. This should be treated in
+the same way as a 1 return value from L<SSL_read_ex(3)>. You should continue to
+call SSL_read_early_data() to read more data.
+
+=item SSL_READ_EARLY_DATA_FINISH
+
+This indicates that no more early data can be read. It may be returned on the
+first call to SSL_read_early_data() if the client has not sent any early data,
+or if the early data was rejected.
+
+=back
+
+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
+supports 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)>, 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().
+
+Calls to SSL_read_early_data() may, in certain circumstances, complete the
+connection immediately without further need to call a function such as
+L<SSL_accept(3)>. This can happen if the client is using a protocol version less
+than TLSv1.3. Applications can test for this by calling
+L<SSL_is_init_finished(3)>. Alternatively, applications may choose to call
+L<SSL_accept(3)> anway. Such a call will successfully return immediately with no
+further action taken.
+
+When a session is created between a server and a client the server will specify
+the maximum amount of any early data that it will accept on any future
+connection attempt. By default this is approximately 16k. A server may override
+this default value by calling SSL_CTX_set_max_early_data() or
+SSL_set_max_early_data() to set it for the whole SSL_CTX or an individual SSL
+object respectively. Similarly the SSL_CTX_get_max_early_data() and
+SSL_get_max_early_data() functions can be used to obtain the current maximum
+early data settings for the SSL_CTX and SSL objects respectively.
+
+In the event that the current maximum early data setting for the server is
+different to that originally specified in a session that a client is resuming
+with then the lower of the two values will apply.
+
+=head1 RETURN VALUES
+
+SSL_write_early_data() returns 1 for success or 0 for failure. In the event of a
+failure call L<SSL_get_error(3)> to determine the correct course of action.
+
+SSL_read_early_data() returns SSL_READ_EARLY_DATA_ERROR for failure,
+SSL_READ_EARLY_DATA_SUCCESS for success with more data to read and
+SSL_READ_EARLY_DATA_FINISH for success with no more to data be read. In the
+event of a failure call L<SSL_get_error(3)> to determine the correct course of
+action.
+
+SSL_get_max_early_data(), SSL_CTX_get_max_early_data() and
+SSL_SESSION_get_max_early_data() return the maximum number of early data bytes
+that may be sent.
+
+SSL_set_max_early_data() and SSL_CTX_set_max_early_data() return 1 for success
+or 0 for failure.
+
+SSL_get_early_data_status() returns SSL_EARLY_DATA_ACCEPTED if early data was
+accepted by the server, SSL_EARLY_DATA_REJECTED if early data was rejected by
+the server, or SSL_EARLY_DATA_NOT_SENT if no early data was sent.
+
+=head1 SEE ALSO
+
+L<SSL_get_error(3)>,
+L<SSL_write_ex(3)>,
+L<SSL_read_ex(3)>,
+L<SSL_connect(3)>,
+L<SSL_accept(3)>,
+L<SSL_do_handshake(3)>,
+L<ssl(7)>
+
+=head1 HISTORY
+
+All of the functions described above were added in OpenSSL 1.1.1.
+
+=head1 COPYRIGHT
+
+Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 9e87c6b..2b4464c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -797,6 +797,11 @@ void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb);
*/
SSL_CTX_keylog_cb_func SSL_CTX_get_keylog_callback(const SSL_CTX *ctx);
+int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data);
+uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx);
+int SSL_set_max_early_data(SSL *s, uint32_t max_early_data);
+uint32_t SSL_get_max_early_data(const SSL_CTX *s);
+
#ifdef __cplusplus
}
#endif
@@ -894,7 +899,9 @@ typedef enum {
TLS_ST_SW_KEY_UPDATE,
TLS_ST_CW_KEY_UPDATE,
TLS_ST_SR_KEY_UPDATE,
- TLS_ST_CR_KEY_UPDATE
+ TLS_ST_CR_KEY_UPDATE,
+ TLS_ST_EARLY_DATA,
+ TLS_ST_PENDING_EARLY_DATA_END
} OSSL_HANDSHAKE_STATE;
/*
@@ -1020,6 +1027,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
# define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR
# define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED
# define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION
+# define SSL_AD_END_OF_EARLY_DATA TLS13_AD_END_OF_EARLY_DATA
# define SSL_AD_MISSING_EXTENSION TLS13_AD_MISSING_EXTENSION
# define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
# define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
@@ -1432,6 +1440,7 @@ __owur int SSL_SESSION_has_ticket(const SSL_SESSION *s);
__owur unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s);
void SSL_SESSION_get0_ticket(const SSL_SESSION *s, const unsigned char **tick,
size_t *len);
+__owur uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s);
__owur int SSL_copy_session_id(SSL *to, const SSL *from);
__owur X509 *SSL_SESSION_get0_peer(SSL_SESSION *s);
__owur int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx,
@@ -1605,15 +1614,30 @@ __owur int SSL_accept(SSL *ssl);
__owur int SSL_connect(SSL *ssl);
__owur int SSL_read(SSL *ssl, void *buf, int num);
__owur int SSL_read_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
+
+# define SSL_READ_EARLY_DATA_ERROR 0
+# define SSL_READ_EARLY_DATA_SUCCESS 1
+# define SSL_READ_EARLY_DATA_FINISH 2
+
+__owur int SSL_read_early_data(SSL *s, void *buf, size_t num,
+ size_t *readbytes);
__owur int SSL_peek(SSL *ssl, void *buf, int num);
__owur int SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
__owur int SSL_write(SSL *ssl, const void *buf, int num);
__owur int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written);
+__owur int SSL_write_early_data(SSL *s, const void *buf, size_t num,
+ size_t *written);
long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg);
long SSL_callback_ctrl(SSL *, int, void (*)(void));
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg);
long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void));
+# define SSL_EARLY_DATA_NOT_SENT 0
+# define SSL_EARLY_DATA_REJECTED 1
+# define SSL_EARLY_DATA_ACCEPTED 2
+
+__owur int SSL_get_early_data_status(const SSL *s);
+
__owur int SSL_get_error(const SSL *s, int ret_code);
__owur const char *SSL_get_version(const SSL *s);
@@ -2133,6 +2157,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST 385
# define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE 370
# define SSL_F_DTLS_PROCESS_HELLO_VERIFY 386
+# define SSL_F_EARLY_DATA_COUNT_OK 532
# define SSL_F_FINAL_EC_PT_FORMATS 485
# define SSL_F_FINAL_EMS 486
# define SSL_F_FINAL_KEY_SHARE 503
@@ -2246,6 +2271,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_PEEK_EX 432
# define SSL_F_SSL_PEEK_INTERNAL 522
# define SSL_F_SSL_READ 223
+# define SSL_F_SSL_READ_EARLY_DATA 529
# define SSL_F_SSL_READ_EX 434
# define SSL_F_SSL_READ_INTERNAL 523
# define SSL_F_SSL_RENEGOTIATE 516
@@ -2285,6 +2311,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_VALIDATE_CT 400
# define SSL_F_SSL_VERIFY_CERT_CHAIN 207
# define SSL_F_SSL_WRITE 208
+# define SSL_F_SSL_WRITE_EARLY_DATA 526
+# define SSL_F_SSL_WRITE_EARLY_FINISH 527
# define SSL_F_SSL_WRITE_EX 433
# define SSL_F_SSL_WRITE_INTERNAL 524
# define SSL_F_STATE_MACHINE 353
@@ -2319,6 +2347,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY 489
# define SSL_F_TLS_CONSTRUCT_CTOS_ALPN 466
# define SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE 355
+# define SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA 530
# define SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS 467
# define SSL_F_TLS_CONSTRUCT_CTOS_EMS 468
# define SSL_F_TLS_CONSTRUCT_CTOS_ETM 469
@@ -2355,6 +2384,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE 374
# define SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG 452
# define SSL_F_TLS_CONSTRUCT_STOC_DONE 375
+# define SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA 531
+# define SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO 525
# define SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS 453
# define SSL_F_TLS_CONSTRUCT_STOC_EMS 454
# define SSL_F_TLS_CONSTRUCT_STOC_ETM 455
@@ -2376,6 +2407,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_PARSE_CTOS_PSK 505
# define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 464
# define SSL_F_TLS_PARSE_CTOS_USE_SRTP 465
+# define SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO 528
# define SSL_F_TLS_PARSE_STOC_KEY_SHARE 445
# define SSL_F_TLS_PARSE_STOC_PSK 502
# define SSL_F_TLS_PARSE_STOC_RENEGOTIATE 448
@@ -2519,6 +2551,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_INVALID_CONFIGURATION_NAME 113
# define SSL_R_INVALID_CT_VALIDATION_TYPE 212
# define SSL_R_INVALID_KEY_UPDATE_TYPE 120
+# define SSL_R_INVALID_MAX_EARLY_DATA 174
# define SSL_R_INVALID_NULL_CMD_NAME 385
# define SSL_R_INVALID_SEQUENCE_NUMBER 402
# define SSL_R_INVALID_SERVERINFO_DATA 388
@@ -2650,10 +2683,12 @@ int ERR_load_SSL_strings(void);
# define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157
# define SSL_R_TOO_MANY_KEY_UPDATES 132
# define SSL_R_TOO_MANY_WARN_ALERTS 409
+# define SSL_R_TOO_MUCH_EARLY_DATA 164
# define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314
# define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239
# define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242
# define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243
+# define SSL_R_UNEXPECTED_END_OF_EARLY_DATA 178
# define SSL_R_UNEXPECTED_MESSAGE 244
# define SSL_R_UNEXPECTED_RECORD 245
# define SSL_R_UNINITIALIZED 276
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 5948dfb..e6df97b 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -299,12 +299,13 @@ extern "C" {
# define SSL3_MT_CCS 1
/* These are used when changing over to a new cipher */
-# define SSL3_CC_READ 0x01
-# define SSL3_CC_WRITE 0x02
-# define SSL3_CC_CLIENT 0x10
-# define SSL3_CC_SERVER 0x20
-# define SSL3_CC_HANDSHAKE 0x40
-# define SSL3_CC_APPLICATION 0x80
+# define SSL3_CC_READ 0x001
+# define SSL3_CC_WRITE 0x002
+# define SSL3_CC_CLIENT 0x010
+# define SSL3_CC_SERVER 0x020
+# define SSL3_CC_EARLY 0x040
+# define SSL3_CC_HANDSHAKE 0x080
+# define SSL3_CC_APPLICATION 0x100
# define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE)
# define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ)
# define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ)
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 6902f50..1054487 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -104,6 +104,7 @@ extern "C" {
# define TLS1_AD_USER_CANCELLED 90
# define TLS1_AD_NO_RENEGOTIATION 100
/* TLSv1.3 alerts */
+# define TLS13_AD_END_OF_EARLY_DATA 1
# define TLS13_AD_MISSING_EXTENSION 109 /* fatal */
/* codes 110-114 are from RFC3546 */
# define TLS1_AD_UNSUPPORTED_EXTENSION 110
@@ -178,8 +179,10 @@ extern "C" {
/* As defined for TLS1.3 */
# define TLSEXT_TYPE_key_share 40
# define TLSEXT_TYPE_psk 41
+# define TLSEXT_TYPE_early_data 42
# define TLSEXT_TYPE_supported_versions 43
# define TLSEXT_TYPE_psk_kex_modes 45
+# define TLSEXT_TYPE_early_data_info 46
/* Temporary extension type */
# define TLSEXT_TYPE_renegotiate 0xff01
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 5aea4b3..2cdc62d 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -348,6 +348,10 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
return -1;
}
+ if (s->early_data_state == SSL_EARLY_DATA_WRITING
+ && !early_data_count_ok(s, len, 0, NULL))
+ return -1;
+
s->rlayer.wnum = 0;
if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) {
@@ -745,7 +749,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
}
/* Explicit IV length, block ciphers appropriate version flag */
- if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)) {
+ if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s) && !SSL_TREAT_AS_TLS13(s)) {
int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
if (mode == EVP_CIPH_CBC_MODE) {
/* TODO(size_t): Convert me */
@@ -764,7 +768,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
/* Clear our SSL3_RECORD structures */
memset(wr, 0, sizeof wr);
for (j = 0; j < numpipes; j++) {
- unsigned int version = SSL_IS_TLS13(s) ? TLS1_VERSION : s->version;
+ unsigned int version = SSL_TREAT_AS_TLS13(s) ? TLS1_VERSION : s->version;
unsigned char *compressdata = NULL;
size_t maxcomplen;
unsigned int rectype;
@@ -777,7 +781,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
* In TLSv1.3, once encrypting, we always use application data for the
* record type
*/
- if (SSL_IS_TLS13(s) && s->enc_write_ctx != NULL)
+ if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL)
rectype = SSL3_RT_APPLICATION_DATA;
else
rectype = type;
@@ -835,7 +839,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
SSL3_RECORD_reset_input(&wr[j]);
}
- if (SSL_IS_TLS13(s) && s->enc_write_ctx != NULL) {
+ if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
if (!WPACKET_put_bytes_u8(thispkt, type)) {
SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
goto err;
@@ -887,8 +891,17 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
SSL3_RECORD_set_length(thiswr, len);
}
- if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1)
- goto err;
+ if (s->early_data_state == SSL_EARLY_DATA_WRITING) {
+ /*
+ * We haven't actually negotiated the version yet, but we're trying to
+ * send early data - so we need to use the the tls13enc function.
+ */
+ if (tls13_enc(s, wr, numpipes, 1) < 1)
+ goto err;
+ } else {
+ if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1)
+ goto err;
+ }
for (j = 0; j < numpipes; j++) {
size_t origlen;
@@ -1428,6 +1441,14 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
al = SSL_AD_HANDSHAKE_FAILURE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_NO_RENEGOTIATION);
goto f_err;
+ } else if (alert_descr == SSL_AD_END_OF_EARLY_DATA) {
+ if (!ssl_end_of_early_data_seen(s)) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,
+ SSL_R_UNEXPECTED_END_OF_EARLY_DATA);
+ goto f_err;
+ }
+ return 0;
}
} else if (alert_level == SSL3_AL_FATAL) {
char tmp[16];
@@ -1548,6 +1569,21 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
if (ossl_statem_app_data_allowed(s)) {
s->s3->in_read_app_data = 2;
return -1;
+ } else if (ossl_statem_skip_early_data(s)) {
+ /*
+ * This can happen after a client sends a CH followed by early_data,
+ * but the server responds with a HelloRetryRequest. The server
+ * reads the next record from the client expecting to find a
+ * plaintext ClientHello but gets a record which appears to be
+ * application data. The trial decrypt "works" because null
+ * decryption was applied. We just skip it and move on to the next
+ * record.
+ */
+ if (!early_data_count_ok(s, rr->length,
+ EARLY_DATA_CIPHERTEXT_OVERHEAD, &al))
+ goto f_err;
+ SSL3_RECORD_set_read(rr);
+ goto start;
} else {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD);
diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h
index 6394835..e249918 100644
--- a/ssl/record/record_locl.h
+++ b/ssl/record/record_locl.h
@@ -115,3 +115,4 @@ __owur int tls1_cbc_remove_padding(const SSL *s,
size_t block_size, size_t mac_size);
int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
__owur int dtls1_get_record(SSL *s);
+int early_data_count_ok(SSL *s, size_t length, size_t overhead, int *al);
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 3868bb5..4149969 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -101,6 +101,40 @@ static int ssl3_record_app_data_waiting(SSL *s)
return 1;
}
+int early_data_count_ok(SSL *s, size_t length, size_t overhead, int *al)
+{
+ uint32_t max_early_data = s->max_early_data;
+
+ /*
+ * If we are a client then we always use the max_early_data from the
+ * session. Otherwise we go with the lowest out of the max early data set in
+ * the session and the configured max_early_data.
+ */
+ if (!s->server || (s->hit
+ && s->session->ext.max_early_data < s->max_early_data))
+ max_early_data = s->session->ext.max_early_data;
+
+ if (max_early_data == 0) {
+ if (al != NULL)
+ *al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_EARLY_DATA_COUNT_OK, SSL_R_TOO_MUCH_EARLY_DATA);
+ return 0;
+ }
+
+ /* If we are dealing with ciphertext we need to allow for the overhead */
+ max_early_data += overhead;
+
+ if (s->early_data_count + length > max_early_data) {
+ if (al != NULL)
+ *al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_EARLY_DATA_COUNT_OK, SSL_R_TOO_MUCH_EARLY_DATA);
+ return 0;
+ }
+ s->early_data_count += length;
+
+ return 1;
+}
+
/*
* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that
* will be processed per call to ssl3_get_record. Without this limit an
@@ -139,6 +173,7 @@ int ssl3_get_record(SSL *s)
int imac_size;
size_t num_recs = 0, max_recs, j;
PACKET pkt, sslv2pkt;
+ size_t first_rec_len;
rr = RECORD_LAYER_get_rrec(&s->rlayer);
rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
@@ -415,15 +450,35 @@ int ssl3_get_record(SSL *s)
}
}
+ first_rec_len = rr[0].length;
+
enc_err = s->method->ssl3_enc->enc(s, rr, num_recs, 0);
/*-
* enc_err is:
- * 0: (in non-constant time) if the record is publically invalid.
+ * 0: (in non-constant time) if the record is publicly invalid.
* 1: if the padding is valid
* -1: if the padding is invalid
*/
if (enc_err == 0) {
+ if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
+ /*
+ * Valid early_data that we cannot decrypt might fail here as
+ * publicly invalid. We treat it like an empty record.
+ */
+
+ thisrr = &rr[0];
+
+ if (!early_data_count_ok(s, thisrr->length,
+ EARLY_DATA_CIPHERTEXT_OVERHEAD, &al))
+ goto f_err;
+
+ thisrr->length = 0;
+ thisrr->read = 1;
+ RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+ RECORD_LAYER_reset_read_sequence(&s->rlayer);
+ return 1;
+ }
al = SSL_AD_DECRYPTION_FAILED;
SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
goto f_err;
@@ -496,6 +551,27 @@ int ssl3_get_record(SSL *s)
}
if (enc_err < 0) {
+ if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
+ /*
+ * We assume this is unreadable early_data - we treat it like an
+ * empty record
+ */
+
+ /*
+ * The record length may have been modified by the mac check above
+ * so we use the previously saved value
+ */
+ if (!early_data_count_ok(s, first_rec_len,
+ EARLY_DATA_CIPHERTEXT_OVERHEAD, &al))
+ goto f_err;
+
+ thisrr = &rr[0];
+ thisrr->length = 0;
+ thisrr->read = 1;
+ RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+ RECORD_LAYER_reset_read_sequence(&s->rlayer);
+ return 1;
+ }
/*
* A separate 'decryption_failed' alert was introduced with TLS 1.0,
* SSL 3.0 only has 'bad_record_mac'. But unless a decryption
@@ -580,6 +656,13 @@ int ssl3_get_record(SSL *s)
}
}
+ if (s->early_data_state == SSL_EARLY_DATA_READING) {
+ thisrr = &rr[0];
+ if (thisrr->type == SSL3_RT_APPLICATION_DATA
+ && !early_data_count_ok(s, thisrr->length, 0, &al))
+ goto f_err;
+ }
+
RECORD_LAYER_set_numrpipes(&s->rlayer, num_recs);
return 1;
diff --git a/ssl/record/ssl3_record_tls13.c b/ssl/record/ssl3_record_tls13.c
index d96a042..87041df 100644
--- a/ssl/record/ssl3_record_tls13.c
+++ b/ssl/record/ssl3_record_tls13.c
@@ -56,14 +56,18 @@ int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send)
ivlen = EVP_CIPHER_CTX_iv_length(ctx);
- /*
- * To get here we must have selected a ciphersuite - otherwise ctx would
- * be NULL
- */
- assert(s->s3->tmp.new_cipher != NULL);
- if (s->s3->tmp.new_cipher == NULL)
- return -1;
- alg_enc = s->s3->tmp.new_cipher->algorithm_enc;
+ if (s->early_data_state == SSL_EARLY_DATA_WRITING) {
+ alg_enc = s->session->cipher->algorithm_enc;
+ } else {
+ /*
+ * To get here we must have selected a ciphersuite - otherwise ctx would
+ * be NULL
+ */
+ assert(s->s3->tmp.new_cipher != NULL);
+ if (s->s3->tmp.new_cipher == NULL)
+ return -1;
+ alg_enc = s->s3->tmp.new_cipher->algorithm_enc;
+ }
if (alg_enc & SSL_AESCCM) {
if (alg_enc & (SSL_AES128CCM8 | SSL_AES256CCM8))
diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c
index 743a02b..7af2f99 100644
--- a/ssl/s3_msg.c
+++ b/ssl/s3_msg.c
@@ -63,7 +63,10 @@ int ssl3_do_change_cipher_spec(SSL *s)
int ssl3_send_alert(SSL *s, int level, int desc)
{
/* Map tls/ssl alert value to correct one */
- desc = s->method->ssl3_enc->alert_value(desc);
+ if (SSL_TREAT_AS_TLS13(s))
+ desc = tls13_alert_code(desc);
+ else
+ desc = s->method->ssl3_enc->alert_value(desc);
if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have
* protocol_version alerts */
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 8141471..856db20 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -65,6 +65,8 @@ typedef struct {
ASN1_OCTET_STRING *srp_username;
#endif
long flags;
+ uint32_t max_early_data;
+ ASN1_OCTET_STRING *alpn_selected;
} SSL_SESSION_ASN1;
ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
@@ -91,7 +93,9 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
ASN1_EXP_OPT(SSL_SESSION_ASN1, srp_username, ASN1_OCTET_STRING, 12),
#endif
ASN1_EXP_OPT(SSL_SESSION_ASN1, flags, ZLONG, 13),
- ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_tick_age_add, ZLONG, 14)
+ ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_tick_age_add, ZLONG, 14),
+ ASN1_EXP_OPT(SSL_SESSION_ASN1, max_early_data, ZLONG, 15),
+ ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16)
} static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
@@ -132,16 +136,14 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
ASN1_OCTET_STRING comp_id;
unsigned char comp_id_data;
#endif
-
ASN1_OCTET_STRING tlsext_hostname, tlsext_tick;
-
#ifndef OPENSSL_NO_SRP
ASN1_OCTET_STRING srp_username;
#endif
-
#ifndef OPENSSL_NO_PSK
ASN1_OCTET_STRING psk_identity, psk_identity_hint;
#endif
+ ASN1_OCTET_STRING alpn_selected;
long l;
@@ -203,6 +205,13 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
#endif /* OPENSSL_NO_SRP */
as.flags = in->flags;
+ as.max_early_data = in->ext.max_early_data;
+
+ if (in->ext.alpn_selected == NULL)
+ as.alpn_selected = NULL;
+ else
+ ssl_session_oinit(&as.alpn_selected, &alpn_selected,
+ in->ext.alpn_selected, in->ext.alpn_selected_len);
return i2d_SSL_SESSION_ASN1(&as, pp);
@@ -357,6 +366,17 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
#endif /* OPENSSL_NO_SRP */
/* Flags defaults to zero which is fine */
ret->flags = as->flags;
+ ret->ext.max_early_data = as->max_early_data;
+
+ if (as->alpn_selected != NULL) {
+ if (!ssl_session_strndup((char **)&ret->ext.alpn_selected,
+ as->alpn_selected))
+ goto err;
+ ret->ext.alpn_selected_len = as->alpn_selected->length;
+ } else {
+ ret->ext.alpn_selected = NULL;
+ ret->ext.alpn_selected_len = 0;
+ }
M_ASN1_free_of(as, SSL_SESSION_ASN1);
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 70764b3..6fe8e6e 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -52,6 +52,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE),
"dtls_get_reassembled_message"},
{ERR_FUNC(SSL_F_DTLS_PROCESS_HELLO_VERIFY), "dtls_process_hello_verify"},
+ {ERR_FUNC(SSL_F_EARLY_DATA_COUNT_OK), "early_data_count_ok"},
{ERR_FUNC(SSL_F_FINAL_EC_PT_FORMATS), "final_ec_pt_formats"},
{ERR_FUNC(SSL_F_FINAL_EMS), "final_ems"},
{ERR_FUNC(SSL_F_FINAL_KEY_SHARE), "final_key_share"},
@@ -205,6 +206,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_PEEK_EX), "SSL_peek_ex"},
{ERR_FUNC(SSL_F_SSL_PEEK_INTERNAL), "ssl_peek_internal"},
{ERR_FUNC(SSL_F_SSL_READ), "SSL_read"},
+ {ERR_FUNC(SSL_F_SSL_READ_EARLY_DATA), "SSL_read_early_data"},
{ERR_FUNC(SSL_F_SSL_READ_EX), "SSL_read_ex"},
{ERR_FUNC(SSL_F_SSL_READ_INTERNAL), "ssl_read_internal"},
{ERR_FUNC(SSL_F_SSL_RENEGOTIATE), "SSL_renegotiate"},
@@ -253,6 +255,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_VALIDATE_CT), "ssl_validate_ct"},
{ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "ssl_verify_cert_chain"},
{ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
+ {ERR_FUNC(SSL_F_SSL_WRITE_EARLY_DATA), "SSL_write_early_data"},
+ {ERR_FUNC(SSL_F_SSL_WRITE_EARLY_FINISH), "SSL_write_early_finish"},
{ERR_FUNC(SSL_F_SSL_WRITE_EX), "SSL_write_ex"},
{ERR_FUNC(SSL_F_SSL_WRITE_INTERNAL), "ssl_write_internal"},
{ERR_FUNC(SSL_F_STATE_MACHINE), "state_machine"},
@@ -299,6 +303,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_ALPN), "tls_construct_ctos_alpn"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE),
"TLS_CONSTRUCT_CTOS_CERTIFICATE"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA),
+ "tls_construct_ctos_early_data"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS),
"tls_construct_ctos_ec_pt_formats"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EMS), "tls_construct_ctos_ems"},
@@ -357,6 +363,10 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG),
"tls_construct_stoc_cryptopro_bug"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_DONE), "TLS_CONSTRUCT_STOC_DONE"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA),
+ "tls_construct_stoc_early_data"},
+ {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO),
+ "tls_construct_stoc_early_data_info"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS),
"tls_construct_stoc_ec_pt_formats"},
{ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EMS), "tls_construct_stoc_ems"},
@@ -390,6 +400,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE),
"tls_parse_ctos_renegotiate"},
{ERR_FUNC(SSL_F_TLS_PARSE_CTOS_USE_SRTP), "tls_parse_ctos_use_srtp"},
+ {ERR_FUNC(SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO),
+ "tls_parse_stoc_early_data_info"},
{ERR_FUNC(SSL_F_TLS_PARSE_STOC_KEY_SHARE), "tls_parse_stoc_key_share"},
{ERR_FUNC(SSL_F_TLS_PARSE_STOC_PSK), "tls_parse_stoc_psk"},
{ERR_FUNC(SSL_F_TLS_PARSE_STOC_RENEGOTIATE),
@@ -585,6 +597,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_REASON(SSL_R_INVALID_CT_VALIDATION_TYPE),
"invalid ct validation type"},
{ERR_REASON(SSL_R_INVALID_KEY_UPDATE_TYPE), "invalid key update type"},
+ {ERR_REASON(SSL_R_INVALID_MAX_EARLY_DATA), "invalid max early data"},
{ERR_REASON(SSL_R_INVALID_NULL_CMD_NAME), "invalid null cmd name"},
{ERR_REASON(SSL_R_INVALID_SEQUENCE_NUMBER), "invalid sequence number"},
{ERR_REASON(SSL_R_INVALID_SERVERINFO_DATA), "invalid serverinfo data"},
@@ -776,6 +789,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"tls invalid ecpointformat list"},
{ERR_REASON(SSL_R_TOO_MANY_KEY_UPDATES), "too many key updates"},
{ERR_REASON(SSL_R_TOO_MANY_WARN_ALERTS), "too many warn alerts"},
+ {ERR_REASON(SSL_R_TOO_MUCH_EARLY_DATA), "too much early data"},
{ERR_REASON(SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS),
"unable to find ecdh parameters"},
{ERR_REASON(SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS),
@@ -784,6 +798,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"unable to load ssl3 md5 routines"},
{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),
"unable to load ssl3 sha1 routines"},
+ {ERR_REASON(SSL_R_UNEXPECTED_END_OF_EARLY_DATA),
+ "unexpected end of early data"},
{ERR_REASON(SSL_R_UNEXPECTED_MESSAGE), "unexpected message"},
{ERR_REASON(SSL_R_UNEXPECTED_RECORD), "unexpected record"},
{ERR_REASON(SSL_R_UNINITIALIZED), "uninitialized"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 39254f1..fcf4f4d 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -105,6 +105,8 @@ static const struct {
},
};
+static int ssl_write_early_finish(SSL *s);
+
static int dane_ctx_enable(struct dane_ctx_st *dctx)
{
const EVP_MD **mdevp;
@@ -551,6 +553,7 @@ SSL *SSL_new(SSL_CTX *ctx)
s->mode = ctx->mode;
s->max_cert_list = ctx->max_cert_list;
s->references = 1;
+ s->max_early_data = ctx->max_early_data;
/*
* Earlier library versions used to copy the pointer to the CERT, not
@@ -1544,6 +1547,17 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
return 0;
}
+ if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+ || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
+ SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ /*
+ * If we are a client and haven't received the ServerHello etc then we
+ * better do that
+ */
+ ossl_statem_check_finish_init(s, 0);
+
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
struct ssl_async_args args;
int ret;
@@ -1593,6 +1607,78 @@ int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
return ret;
}
+int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+ int ret;
+
+ if (!s->server) {
+ SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return SSL_READ_EARLY_DATA_ERROR;
+ }
+
+ switch (s->early_data_state) {
+ case SSL_EARLY_DATA_NONE:
+ if (!SSL_in_before(s)) {
+ SSLerr(SSL_F_SSL_READ_EARLY_DATA,
+ ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return SSL_READ_EARLY_DATA_ERROR;
+ }
+ /* fall through */
+
+ case SSL_EARLY_DATA_ACCEPT_RETRY:
+ s->early_data_state = SSL_EARLY_DATA_ACCEPTING;
+ ret = SSL_accept(s);
+ if (ret <= 0) {
+ /* NBIO or error */
+ s->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY;
+ return SSL_READ_EARLY_DATA_ERROR;
+ }
+ /* fall through */
+
+ case SSL_EARLY_DATA_READ_RETRY:
+ if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+ s->early_data_state = SSL_EARLY_DATA_READING;
+ ret = SSL_read_ex(s, buf, num, readbytes);
+ /*
+ * Record layer will call ssl_end_of_early_data_seen() if we see
+ * that alert - which updates the early_data_state to
+ * SSL_EARLY_DATA_FINISHED_READING
+ */
+ if (ret > 0 || (ret <= 0 && s->early_data_state
+ != SSL_EARLY_DATA_FINISHED_READING)) {
+ s->early_data_state = SSL_EARLY_DATA_READ_RETRY;
+ return ret > 0 ? SSL_READ_EARLY_DATA_SUCCESS
+ : SSL_READ_EARLY_DATA_ERROR;
+ }
+ } else {
+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+ }
+ *readbytes = 0;
+ return SSL_READ_EARLY_DATA_FINISH;
+
+ default:
+ SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return SSL_READ_EARLY_DATA_ERROR;
+ }
+}
+
+int ssl_end_of_early_data_seen(SSL *s)
+{
+ if (s->early_data_state == SSL_EARLY_DATA_READING
+ || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+ ossl_statem_finish_early_data(s);
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_get_early_data_status(const SSL *s)
+{
+ return s->ext.early_data;
+}
+
static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
{
if (s->handshake_func == NULL) {
@@ -1666,6 +1752,22 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
return -1;
}
+ if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+ /*
+ * We're still writing early data. We need to stop that so we can write
+ * normal data
+ */
+ 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_READ_RETRY) {
+ SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ /* If we are a client and haven't sent the Finished we better do that */
+ ossl_statem_check_finish_init(s, 1);
+
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
int ret;
struct ssl_async_args args;
@@ -1715,6 +1817,77 @@ int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written)
return ret;
}
+int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
+{
+ int ret;
+
+ switch (s->early_data_state) {
+ case SSL_EARLY_DATA_NONE:
+ if (s->server
+ || !SSL_in_before(s)
+ || s->session == NULL
+ || s->session->ext.max_early_data == 0) {
+ SSLerr(SSL_F_SSL_WRITE_EARLY_DATA,
+ ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ /* fall through */
+
+ case SSL_EARLY_DATA_CONNECT_RETRY:
+ s->early_data_state = SSL_EARLY_DATA_CONNECTING;
+ ret = SSL_connect(s);
+ if (ret <= 0) {
+ /* NBIO or error */
+ s->early_data_state = SSL_EARLY_DATA_CONNECT_RETRY;
+ return 0;
+ }
+ /* fall through */
+
+ case SSL_EARLY_DATA_WRITE_RETRY:
+ s->early_data_state = SSL_EARLY_DATA_WRITING;
+ ret = SSL_write_ex(s, buf, num, 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_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+}
+
+static int ssl_write_early_finish(SSL *s)
+{
+ int ret;
+
+ if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY) {
+ SSLerr(SSL_F_SSL_WRITE_EARLY_FINISH, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ s->early_data_state = SSL_EARLY_DATA_WRITING;
+ ret = ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_END_OF_EARLY_DATA);
+ if (ret <= 0) {
+ s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+ return 0;
+ }
+ s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+ /*
+ * We set the enc_write_ctx back to NULL because we may end up writing
+ * in cleartext again if we get a HelloRetryRequest from the server.
+ */
+ EVP_CIPHER_CTX_free(s->enc_write_ctx);
+ s->enc_write_ctx = NULL;
+ ossl_statem_set_in_init(s, 1);
+ return 1;
+}
+
int SSL_shutdown(SSL *s)
{
/*
@@ -2622,6 +2795,12 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
ret->ext.status_type = TLSEXT_STATUSTYPE_nothing;
+ /*
+ * Default max early data is a fully loaded single record. Could be split
+ * across multiple records in practice
+ */
+ ret->max_early_data = SSL3_RT_MAX_PLAIN_LENGTH;
+
return ret;
err:
SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
@@ -3072,6 +3251,15 @@ int SSL_do_handshake(SSL *s)
return -1;
}
+ if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+ int edfin;
+
+ edfin = ssl_write_early_finish(s);
+ if (edfin <= 0)
+ return edfin;
+ }
+ ossl_statem_check_finish_init(s, -1);
+
s->method->ssl_renegotiate_check(s, 0);
if (SSL_in_init(s) || SSL_in_before(s)) {
@@ -4657,3 +4845,27 @@ int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites,
sk_SSL_CIPHER_free(scsvs);
return 0;
}
+
+int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data)
+{
+ ctx->max_early_data = max_early_data;
+
+ return 1;
+}
+
+uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx)
+{
+ return ctx->max_early_data;
+}
+
+int SSL_set_max_early_data(SSL *s, uint32_t max_early_data)
+{
+ s->max_early_data = max_early_data;
+
+ return 1;
+}
+
+uint32_t SSL_get_max_early_data(const SSL_CTX *s)
+{
+ return s->max_early_data;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index c253c99..6811b4f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -349,6 +349,9 @@
&& (s)->method->version >= TLS1_3_VERSION \
&& (s)->method->version != TLS_ANY_VERSION)
+# define SSL_TREAT_AS_TLS13(s) \
+ (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_WRITING)
+
# define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0)
/* See if we need explicit IV */
@@ -575,6 +578,11 @@ struct ssl_session_st {
unsigned long tick_lifetime_hint;
uint32_t tick_age_add;
int tick_identity;
+ /* Max number of bytes that can be sent as early data */
+ uint32_t max_early_data;
+ /* The ALPN protocol selected for this session */
+ unsigned char *alpn_selected;
+ size_t alpn_selected_len;
} ext;
# ifndef OPENSSL_NO_SRP
char *srp_username;
@@ -607,6 +615,41 @@ typedef struct srp_ctx_st {
# endif
+typedef enum {
+ SSL_EARLY_DATA_NONE = 0,
+ SSL_EARLY_DATA_CONNECT_RETRY,
+ 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,
+ SSL_EARLY_DATA_READ_RETRY,
+ SSL_EARLY_DATA_READING,
+ SSL_EARLY_DATA_FINISHED_READING
+} SSL_EARLY_DATA_STATE;
+
+/*
+ * We check that the amount of unreadable early data doesn't exceed
+ * max_early_data. max_early_data is given in plaintext bytes. However if it is
+ * unreadable then we only know the number of ciphertext bytes. We also don't
+ * know how much the overhead should be because it depends on the ciphersuite.
+ * We make a small allowance. We assume 5 records of actual data plus the end
+ * of early data alert record. Each record has a tag and a content type byte.
+ * The longest tag length we know of is EVP_GCM_TLS_TAG_LEN. We don't count the
+ * content of the alert record either which is 2 bytes.
+ */
+# define EARLY_DATA_CIPHERTEXT_OVERHEAD ((6 * (EVP_GCM_TLS_TAG_LEN + 1)) + 2)
+
+/*
+ * The allowance we have between the client's calculated ticket age and our own.
+ * We allow for 10 seconds (units are in ms). If a ticket is presented and the
+ * client's age calculation is different by more than this than our own then we
+ * do not allow that ticket for early_data.
+ */
+# define TICKET_AGE_ALLOWANCE (10 * 1000)
+
#define MAX_COMPRESSIONS_SIZE 255
struct ssl_comp_st {
@@ -922,6 +965,9 @@ struct ssl_ctx_st {
* Wireshark. The callback should log `line` followed by a newline.
*/
SSL_CTX_keylog_cb_func keylog_callback;
+
+ /* The maximum number of bytes that can be sent as early data */
+ uint32_t max_early_data;
};
struct ssl_st {
@@ -971,6 +1017,7 @@ struct ssl_st {
int shutdown;
/* where we are */
OSSL_STATEM statem;
+ SSL_EARLY_DATA_STATE early_data_state;
BUF_MEM *init_buf; /* buffer used during init */
void *init_msg; /* pointer to handshake message body, set by
* ssl3_get_message() */
@@ -1004,6 +1051,7 @@ struct ssl_st {
unsigned char client_finished_secret[EVP_MAX_MD_SIZE];
unsigned char server_finished_secret[EVP_MAX_MD_SIZE];
unsigned char server_finished_hash[EVP_MAX_MD_SIZE];
+ unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE];
unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE];
unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE];
EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
@@ -1158,6 +1206,11 @@ struct ssl_st {
/* Set to one if we have negotiated ETM */
int use_etm;
+
+ /* Are we expecting to receive early data? */
+ int early_data;
+ /* Is the session suitable for early data? */
+ int early_data_ok;
} ext;
/* Parsed form of the ClientHello, kept around across early_cb calls. */
@@ -1218,6 +1271,15 @@ struct ssl_st {
ASYNC_WAIT_CTX *waitctx;
size_t asyncrw;
+ /* The maximum number of plaintext bytes that can be sent as early data */
+ uint32_t max_early_data;
+ /*
+ * The number of bytes of early data received so far. If we accepted early
+ * data then this is a count of the plaintext bytes. If we rejected it then
+ * this is a count of the ciphertext bytes.
+ */
+ uint32_t early_data_count;
+
CRYPTO_RWLOCK *lock;
};
@@ -1724,6 +1786,7 @@ typedef enum tlsext_index_en {
TLSEXT_IDX_renegotiate,
TLSEXT_IDX_server_name,
TLSEXT_IDX_srp,
+ TLSEXT_IDX_early_data_info,
TLSEXT_IDX_ec_point_formats,
TLSEXT_IDX_supported_groups,
TLSEXT_IDX_session_ticket,
@@ -1739,6 +1802,7 @@ typedef enum tlsext_index_en {
TLSEXT_IDX_psk_kex_modes,
TLSEXT_IDX_key_share,
TLSEXT_IDX_cryptopro_bug,
+ TLSEXT_IDX_early_data,
TLSEXT_IDX_padding,
TLSEXT_IDX_psk
} TLSEXT_INDEX;
@@ -1961,6 +2025,7 @@ static ossl_inline int ssl_has_cert(const SSL *s, int idx)
# ifndef OPENSSL_UNIT_TEST
+int ssl_end_of_early_data_seen(SSL *s);
__owur int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes);
__owur int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written);
void ssl_clear_cipher_ctx(SSL *s);
@@ -2170,10 +2235,12 @@ __owur int tls13_hkdf_expand(SSL *s, const EVP_MD *md,
const unsigned char *label, size_t labellen,
const unsigned char *hash,
unsigned char *out, size_t outlen);
-__owur int tls13_derive_key(SSL *s, const unsigned char *secret,
- unsigned char *key, size_t keylen);
-__owur int tls13_derive_iv(SSL *s, const unsigned char *secret,
- unsigned char *iv, size_t ivlen);
+__owur int tls13_derive_key(SSL *s, const EVP_MD *md,
+ const unsigned char *secret, unsigned char *key,
+ size_t keylen);
+__owur int tls13_derive_iv(SSL *s, const EVP_MD *md,
+ const unsigned char *secret, unsigned char *iv,
+ size_t ivlen);
__owur int tls13_derive_finishedkey(SSL *s, const EVP_MD *md,
const unsigned char *secret,
unsigned char *fin, size_t finlen);
@@ -2326,6 +2393,7 @@ __owur int ssl_log_secret(SSL *ssl, const char *label,
const uint8_t *secret, size_t secret_len);
#define MASTER_SECRET_LABEL "CLIENT_RANDOM"
+#define CLIENT_EARLY_LABEL "CLIENT_EARLY_TRAFFIC_SECRET"
#define CLIENT_HANDSHAKE_LABEL "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
#define SERVER_HANDSHAKE_LABEL "SERVER_HANDSHAKE_TRAFFIC_SECRET"
#define CLIENT_APPLICATION_LABEL "CLIENT_TRAFFIC_SECRET_0"
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index be3c4c3..2e69176 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -791,6 +791,7 @@ void SSL_SESSION_free(SSL_SESSION *ss)
#ifndef OPENSSL_NO_SRP
OPENSSL_free(ss->srp_username);
#endif
+ OPENSSL_free(ss->ext.alpn_selected);
CRYPTO_THREAD_lock_free(ss->lock);
OPENSSL_clear_free(ss, sizeof(*ss));
}
@@ -901,6 +902,11 @@ void SSL_SESSION_get0_ticket(const SSL_SESSION *s, const unsigned char **tick,
*tick = s->ext.tick;
}
+uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s)
+{
+ return s->ext.max_early_data;
+}
+
X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
{
return s->peer;
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index c011445..edcfe71 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -7,6 +7,7 @@
* https://www.openssl.org/source/license.html
*/
+#include <string.h>
#include "../ssl_locl.h"
#include "statem_locl.h"
@@ -43,6 +44,7 @@ static int final_key_share(SSL *s, unsigned int context, int sent, int *al);
static int init_srtp(SSL *s, unsigned int context);
#endif
static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al);
+static int final_early_data(SSL *s, unsigned int context, int sent, int *al);
/* Structure to define a built-in extension */
typedef struct extensions_definition_st {
@@ -129,6 +131,12 @@ static const EXTENSION_DEFINITION ext_defs[] = {
#else
INVALID_EXTENSION,
#endif
+ {
+ TLSEXT_TYPE_early_data_info,
+ EXT_TLS1_3_NEW_SESSION_TICKET,
+ NULL, NULL, tls_parse_stoc_early_data_info,
+ tls_construct_stoc_early_data_info, NULL, NULL
+ },
#ifndef OPENSSL_NO_EC
{
TLSEXT_TYPE_ec_point_formats,
@@ -271,6 +279,13 @@ static const EXTENSION_DEFINITION ext_defs[] = {
NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
},
{
+ TLSEXT_TYPE_early_data,
+ EXT_CLIENT_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+ NULL, tls_parse_ctos_early_data, tls_parse_stoc_early_data,
+ tls_construct_stoc_early_data, tls_construct_ctos_early_data,
+ final_early_data
+ },
+ {
/* Must be immediately before pre_shared_key */
/* TODO(TLS1.3): Fix me */
TLSEXT_TYPE_padding,
@@ -1217,3 +1232,31 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
return ret;
}
+
+static int final_early_data(SSL *s, unsigned int context, int sent, int *al)
+{
+ if (!s->server || !sent)
+ return 1;
+
+ if (s->max_early_data == 0
+ || !s->hit
+ || s->session->ext.tick_identity != 0
+ || s->early_data_state != SSL_EARLY_DATA_ACCEPTING
+ || !s->ext.early_data_ok
+ || s->hello_retry_request
+ || s->s3->alpn_selected_len != s->session->ext.alpn_selected_len
+ || memcmp(s->s3->alpn_selected, s->session->ext.alpn_selected,
+ s->s3->alpn_selected_len) != 0){
+ s->ext.early_data = SSL_EARLY_DATA_REJECTED;
+ } else {
+ s->ext.early_data = SSL_EARLY_DATA_ACCEPTED;
+
+ if (!tls13_change_cipher_state(s,
+ SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_SERVER_READ)) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+
+ return 1;
+}
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 09780a9..0af4d1b 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -636,6 +636,32 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
return 1;
}
+int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al)
+{
+ if (s->early_data_state != SSL_EARLY_DATA_CONNECTING
+ || s->session->ext.max_early_data == 0) {
+ s->max_early_data = 0;
+ return 1;
+ }
+ s->max_early_data = s->session->ext.max_early_data;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /*
+ * We set this to rejected here. Later, if the server acknowledges the
+ * extension, we set it to accepted.
+ */
+ s->ext.early_data = SSL_EARLY_DATA_REJECTED;
+
+ return 1;
+}
+
#define F5_WORKAROUND_MIN_MSG_LEN 0xff
#define F5_WORKAROUND_MAX_MSG_LEN 0x200
@@ -879,6 +905,24 @@ int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
return 1;
}
+int tls_parse_stoc_early_data_info(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al)
+{
+ unsigned long max_early_data;
+
+ if (!PACKET_get_net_4(pkt, &max_early_data)
+ || PACKET_remaining(pkt) != 0) {
+ SSLerr(SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO,
+ SSL_R_INVALID_MAX_EARLY_DATA);
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->session->ext.max_early_data = max_early_data;
+
+ return 1;
+}
+
#ifndef OPENSSL_NO_EC
int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al)
@@ -1294,6 +1338,30 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
+int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al)
+{
+ if (PACKET_remaining(pkt) != 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->ext.early_data != SSL_EARLY_DATA_REJECTED
+ || !s->hit
+ || s->session->ext.tick_identity != 0) {
+ /*
+ * If we get here then we didn't send early data, or we didn't resume
+ * using the first identity so the server should not be accepting it.
+ */
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ s->ext.early_data = SSL_EARLY_DATA_ACCEPTED;
+
+ return 1;
+}
+
int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx, int *al)
{
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index ecfd00b..c613143 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -661,6 +661,18 @@ int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
+
+int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al)
+{
+ if (PACKET_remaining(pkt) != 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx, int *al)
{
@@ -669,6 +681,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
SSL_SESSION *sess = NULL;
unsigned int id, i;
const EVP_MD *md = NULL;
+ uint32_t ticket_age, now, agesec, agems;
/*
* If we have no PSK kex mode that we recognise then we can't resume so
@@ -685,16 +698,16 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
for (id = 0; PACKET_remaining(&identities) != 0; id++) {
PACKET identity;
- unsigned long ticket_age;
+ unsigned long ticket_agel;
int ret;
if (!PACKET_get_length_prefixed_2(&identities, &identity)
- || !PACKET_get_net_4(&identities, &ticket_age)) {
+ || !PACKET_get_net_4(&identities, &ticket_agel)) {
*al = SSL_AD_DECODE_ERROR;
return 0;
}
- /* TODO(TLS1.3): Should we validate the ticket age? */
+ ticket_age = (uint32_t)ticket_agel;
ret = tls_decrypt_ticket(s, PACKET_data(&identity),
PACKET_remaining(&identity), NULL, 0, &sess);
@@ -753,6 +766,32 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
}
sess->ext.tick_identity = id;
+
+ now = (uint32_t)time(NULL);
+ agesec = now - (uint32_t)sess->time;
+ agems = agesec * (uint32_t)1000;
+ ticket_age -= sess->ext.tick_age_add;
+
+
+ /*
+ * For simplicity we do our age calculations in seconds. If the client does
+ * it in ms then it could appear that their ticket age is longer than ours
+ * (our ticket age calculation should always be slightly longer than the
+ * client's due to the network latency). Therefore we add 1000ms to our age
+ * calculation to adjust for rounding errors.
+ */
+ if (sess->timeout >= agesec
+ && agems / (uint32_t)1000 == agesec
+ && ticket_age <= agems + 1000
+ && ticket_age + TICKET_AGE_ALLOWANCE >= agems + 1000) {
+ /*
+ * Ticket age is within tolerance and not expired. We allow it for early
+ * data
+ */
+ s->ext.early_data_ok = 1;
+ }
+
+
SSL_SESSION_free(s->session);
s->session = sess;
return 1;
@@ -801,6 +840,24 @@ int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context,
return 1;
}
+int tls_construct_stoc_early_data_info(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx, int *al)
+{
+ if (s->max_early_data == 0)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data_info)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
#ifndef OPENSSL_NO_EC
int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al)
@@ -1090,6 +1147,22 @@ int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
return 1;
}
+int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al)
+{
+ if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED)
+ return 1;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
size_t chainidx, int *al)
{
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index a1c5a21..11cbe55 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -151,6 +151,49 @@ void ossl_statem_set_in_handshake(SSL *s, int inhand)
s->statem.in_handshake--;
}
+/* Are we in a sensible state to skip over unreadable early data? */
+int ossl_statem_skip_early_data(SSL *s)
+{
+ if (s->ext.early_data != SSL_EARLY_DATA_REJECTED)
+ return 0;
+
+ if (s->hello_retry_request) {
+ if (s->statem.hand_state != TLS_ST_SW_HELLO_RETRY_REQUEST)
+ return 0;
+ } else {
+ if (!s->server || s->statem.hand_state != TLS_ST_EARLY_DATA)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Called when we are in SSL_read*(), SSL_write*(), or SSL_accept()
+ * /SSL_connect()/SSL_do_handshake(). Used to test whether we are in an early
+ * data state and whether we should attempt to move the handshake on if so.
+ * |send| is 1 if we are attempting to send data (SSL_write*()), 0 if we are
+ * attempting to read data (SSL_read*()), or -1 if we are in SSL_do_handshake()
+ * or similar.
+ */
+void ossl_statem_check_finish_init(SSL *s, int send)
+{
+ if (send == -1) {
+ if (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+ || s->statem.hand_state == TLS_ST_EARLY_DATA)
+ ossl_statem_set_in_init(s, 1);
+ } else if (!s->server) {
+ if ((send && s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+ && s->early_data_state != SSL_EARLY_DATA_WRITING)
+ || (!send && s->statem.hand_state == TLS_ST_EARLY_DATA))
+ ossl_statem_set_in_init(s, 1);
+ } else {
+ if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING
+ && s->statem.hand_state == TLS_ST_EARLY_DATA)
+ ossl_statem_set_in_init(s, 1);
+ }
+}
+
void ossl_statem_set_hello_verify_done(SSL *s)
{
s->statem.state = MSG_FLOW_UNINITED;
@@ -313,7 +356,8 @@ static int state_machine(SSL *s, int server)
goto end;
}
- if (SSL_IS_FIRST_HANDSHAKE(s) || s->renegotiate) {
+ if ((SSL_in_before(s))
+ || s->renegotiate) {
if (!tls_setup_handshake(s)) {
ossl_statem_set_error(s);
goto end;
@@ -717,8 +761,17 @@ static SUB_STATE_RETURN write_state_machine(SSL *s)
case WORK_FINISHED_STOP:
return SUB_STATE_END_HANDSHAKE;
}
+ if (!get_construct_message_f(s, &pkt, &confunc, &mt)) {
+ ossl_statem_set_error(s);
+ return SUB_STATE_ERROR;
+ }
+ if (mt == SSL3_MT_DUMMY) {
+ /* Skip construction and sending. This isn't a "real" state */
+ st->write_state = WRITE_STATE_POST_WORK;
+ st->write_state_work = WORK_MORE_A;
+ break;
+ }
if (!WPACKET_init(&pkt, s->init_buf)
- || !get_construct_message_f(s, &pkt, &confunc, &mt)
|| !ssl_set_handshake_header(s, &pkt, mt)
|| (confunc != NULL && !confunc(s, &pkt))
|| !ssl_close_construct_packet(s, &pkt, mt)
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
index 906f2ec..56009b0 100644
--- a/ssl/statem/statem.h
+++ b/ssl/statem/statem.h
@@ -122,9 +122,12 @@ int ossl_statem_in_error(const SSL *s);
void ossl_statem_set_in_init(SSL *s, int init);
int ossl_statem_get_in_handshake(SSL *s);
void ossl_statem_set_in_handshake(SSL *s, int inhand);
+__owur int ossl_statem_skip_early_data(SSL *s);
+void ossl_statem_check_finish_init(SSL *s, int send);
void ossl_statem_set_hello_verify_done(SSL *s);
__owur int ossl_statem_app_data_allowed(SSL *s);
#ifndef OPENSSL_NO_SCTP
void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock);
__owur int ossl_statem_in_sctp_read_sock(SSL *s);
#endif
+int ossl_statem_finish_early_data(SSL *s);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index abddc0a..b11cd19 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -124,11 +124,6 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
OSSL_STATEM *st = &s->statem;
/*
- * TODO(TLS1.3): This is still based on the TLSv1.2 state machine. Over time
- * we will update this to look more like real TLSv1.3
- */
-
- /*
* Note: There is no case for TLS_ST_CW_CLNT_HELLO, because we haven't
* yet negotiated TLSv1.3 at that point so that is handled by
* ossl_statem_client_read_transition()
@@ -258,6 +253,22 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
}
break;
+ case TLS_ST_EARLY_DATA:
+ /*
+ * We've not actually selected TLSv1.3 yet, but we have sent early
+ * data. The only thing allowed now is a ServerHello or a
+ * HelloRetryRequest.
+ */
+ if (mt == SSL3_MT_SERVER_HELLO) {
+ st->hand_state = TLS_ST_CR_SRVR_HELLO;
+ return 1;
+ }
+ if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
+ st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST;
+ return 1;
+ }
+ break;
+
case TLS_ST_CR_SRVR_HELLO:
if (s->hit) {
if (s->ext.ticket_expected) {
@@ -424,6 +435,14 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
case TLS_ST_CR_FINISHED:
+ if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
+ st->hand_state = TLS_ST_PENDING_EARLY_DATA_END;
+ else
+ st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
+ : TLS_ST_CW_FINISHED;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_PENDING_EARLY_DATA_END:
st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
: TLS_ST_CW_FINISHED;
return WRITE_TRAN_CONTINUE;
@@ -449,7 +468,6 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
case TLS_ST_CR_SESSION_TICKET:
case TLS_ST_CW_FINISHED:
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
case TLS_ST_OK:
@@ -498,12 +516,23 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
case TLS_ST_CW_CLNT_HELLO:
+ if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) {
+ /*
+ * We are assuming this is a TLSv1.3 connection, although we haven't
+ * actually selected a version yet.
+ */
+ st->hand_state = TLS_ST_EARLY_DATA;
+ return WRITE_TRAN_CONTINUE;
+ }
/*
* No transition at the end of writing because we don't know what
* we will be sent
*/
return WRITE_TRAN_FINISHED;
+ case TLS_ST_EARLY_DATA:
+ return WRITE_TRAN_FINISHED;
+
case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
st->hand_state = TLS_ST_CW_CLNT_HELLO;
return WRITE_TRAN_CONTINUE;
@@ -546,7 +575,8 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
case TLS_ST_CW_CHANGE:
#if defined(OPENSSL_NO_NEXTPROTONEG)
- st->hand_state = TLS_ST_CW_FINISHED;
+ st->
+ hand_state = TLS_ST_CW_FINISHED;
#else
if (!SSL_IS_DTLS(s) && s->s3->npn_seen)
st->hand_state = TLS_ST_CW_NEXT_PROTO;
@@ -564,7 +594,6 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
case TLS_ST_CW_FINISHED:
if (s->hit) {
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
} else {
return WRITE_TRAN_FINISHED;
@@ -576,7 +605,6 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
} else {
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
}
@@ -594,7 +622,6 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
}
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
}
}
@@ -639,6 +666,8 @@ WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
}
break;
+ case TLS_ST_EARLY_DATA:
+ case TLS_ST_PENDING_EARLY_DATA_END:
case TLS_ST_OK:
return tls_finish_handshake(s, wst, 1);
}
@@ -669,6 +698,18 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
/* Treat the next message as the first packet */
s->first_packet = 1;
}
+
+ if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
+ && s->max_early_data > 0) {
+ /*
+ * We haven't selected TLSv1.3 yet so we don't call the change
+ * cipher state function associated with the SSL_METHOD. Instead
+ * we call tls13_change_cipher_state() directly.
+ */
+ if (!tls13_change_cipher_state(s,
+ SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+ return WORK_ERROR;
+ }
break;
case TLS_ST_CW_KEY_EXCH:
@@ -999,9 +1040,6 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
}
/* else use the pre-loaded session */
- /* This is a real handshake so make sure we clean it up at the end */
- s->statem.cleanuphand = 1;
-
p = s->s3->client_random;
/*
@@ -1476,8 +1514,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
if (SSL_IS_TLS13(s)
&& (!s->method->ssl3_enc->setup_key_block(s)
|| !s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE)
- || !s->method->ssl3_enc->change_cipher_state(s,
SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_READ))) {
al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_CANNOT_CHANGE_CIPHER);
@@ -3234,11 +3270,22 @@ int tls_construct_client_certificate(SSL *s, WPACKET *pkt)
: s->cert->key,
&al)) {
SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- return 0;
+ goto err;
+ }
+
+ if (SSL_IS_TLS13(s)
+ && SSL_IS_FIRST_HANDSHAKE(s)
+ && (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE,
+ SSL_R_CANNOT_CHANGE_CIPHER);
+ goto err;
}
return 1;
+ err:
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return 0;
}
#define has_bits(i,m) (((i)&(m)) == (m))
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index ed1ecce..32bcad4 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -442,6 +442,23 @@ int tls_construct_finished(SSL *s, WPACKET *pkt)
const char *sender;
size_t slen;
+ /* This is a real handshake so make sure we clean it up at the end */
+ if (!s->server)
+ s->statem.cleanuphand = 1;
+
+ /*
+ * We only change the keys if we didn't already do this when we sent the
+ * client certificate
+ */
+ if (SSL_IS_TLS13(s)
+ && !s->server
+ && s->s3->tmp.cert_req == 0
+ && (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
+ goto err;
+ }
+
if (s->server) {
sender = s->method->ssl3_enc->server_finished_label;
slen = s->method->ssl3_enc->server_finished_label_len;
@@ -654,6 +671,11 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
int al = SSL_AD_INTERNAL_ERROR;
size_t md_len;
+
+ /* This is a real handshake so make sure we clean it up at the end */
+ if (s->server)
+ s->statem.cleanuphand = 1;
+
/* If this occurs, we have missed a message */
if (!SSL_IS_TLS13(s) && !s->s3->change_cipher_spec) {
al = SSL_AD_UNEXPECTED_MESSAGE;
@@ -944,6 +966,7 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs)
s->d1->next_handshake_write_seq = 0;
dtls1_clear_received_buffer(s);
}
+ s->early_data_state = SSL_EARLY_DATA_NONE;
}
/*
@@ -953,6 +976,7 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs)
if (!clearbufs)
return WORK_FINISHED_CONTINUE;
+ ossl_statem_set_in_init(s, 0);
return WORK_FINISHED_STOP;
}
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index 9230332..c52ce2b 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -53,6 +53,9 @@
#define EXT_TLS1_3_CERTIFICATE 0x0800
#define EXT_TLS1_3_NEW_SESSION_TICKET 0x1000
+/* Dummy message type */
+#define SSL3_MT_DUMMY -1
+
/* Message processing return codes */
typedef enum {
/* Something bad happened */
@@ -191,6 +194,8 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx, int *al);
#endif
+int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
#ifndef OPENSSL_NO_EC
int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
@@ -230,6 +235,11 @@ int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
+int tls_construct_stoc_early_data_info(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx, int *al);
+int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
#ifndef OPENSSL_NO_EC
int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
@@ -285,6 +295,8 @@ int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx, int *al);
#endif
+int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx, int *al);
@@ -328,6 +340,10 @@ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
+int tls_parse_stoc_early_data_info(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
+int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
#ifndef OPENSSL_NO_EC
int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx, int *al);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 39e0f59..7414c19 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -93,6 +93,7 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
}
break;
+ case TLS_ST_EARLY_DATA:
case TLS_ST_SW_FINISHED:
if (s->s3->tmp.cert_request) {
if (mt == SSL3_MT_CERTIFICATE) {
@@ -129,6 +130,12 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
break;
case TLS_ST_OK:
+ /*
+ * Its never ok to start processing handshake messages in the middle of
+ * early data (i.e. before we've received the end of early data alert)
+ */
+ if (s->early_data_state == SSL_EARLY_DATA_READING)
+ break;
if (mt == SSL3_MT_KEY_UPDATE) {
st->hand_state = TLS_ST_SR_KEY_UPDATE;
return 1;
@@ -450,6 +457,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
case TLS_ST_SW_FINISHED:
+ st->hand_state = TLS_ST_EARLY_DATA;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_EARLY_DATA:
return WRITE_TRAN_FINISHED;
case TLS_ST_SR_FINISHED:
@@ -474,7 +485,6 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
case TLS_ST_SW_KEY_UPDATE:
case TLS_ST_SW_SESSION_TICKET:
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
}
}
@@ -520,7 +530,6 @@ WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
case TLS_ST_SW_HELLO_REQ:
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
case TLS_ST_SR_CLNT_HELLO:
@@ -587,7 +596,6 @@ WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
case TLS_ST_SR_FINISHED:
if (s->hit) {
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
} else if (s->ext.ticket_expected) {
st->hand_state = TLS_ST_SW_SESSION_TICKET;
@@ -609,7 +617,6 @@ WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
return WRITE_TRAN_FINISHED;
}
st->hand_state = TLS_ST_OK;
- ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
}
}
@@ -693,6 +700,11 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
}
return WORK_FINISHED_CONTINUE;
+ case TLS_ST_EARLY_DATA:
+ if (s->early_data_state != SSL_EARLY_DATA_ACCEPTING)
+ return WORK_FINISHED_CONTINUE;
+ /* Fall through */
+
case TLS_ST_OK:
return tls_finish_handshake(s, wst, 1);
}
@@ -778,10 +790,13 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
if (SSL_IS_TLS13(s)) {
if (!s->method->ssl3_enc->setup_key_block(s)
|| !s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_WRITE)
- || !s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_WRITE))
+ return WORK_ERROR;
+
+ if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED
+ && !s->method->ssl3_enc->change_cipher_state(s,
SSL3_CC_HANDSHAKE |SSL3_CHANGE_CIPHER_SERVER_READ))
- return WORK_ERROR;
+ return WORK_ERROR;
}
break;
@@ -934,6 +949,11 @@ int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt,
*mt = SSL3_MT_FINISHED;
break;
+ case TLS_ST_EARLY_DATA:
+ *confunc = NULL;
+ *mt = SSL3_MT_DUMMY;
+ break;
+
case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
*confunc = tls_construct_encrypted_extensions;
*mt = SSL3_MT_ENCRYPTED_EXTENSIONS;
@@ -1095,6 +1115,15 @@ WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst)
return WORK_FINISHED_CONTINUE;
}
+int ossl_statem_finish_early_data(SSL *s)
+{
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ))
+ return 0;
+
+ return 1;
+}
+
#ifndef OPENSSL_NO_SRP
static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
{
@@ -1234,9 +1263,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
s->new_session = 1;
}
- /* This is a real handshake so make sure we clean it up at the end */
- s->statem.cleanuphand = 1;
-
/*
* First, parse the raw ClientHello data into the CLIENTHELLO_MSG structure.
*/
@@ -3376,6 +3402,19 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0)
goto err;
s->session->ext.tick_age_add = age_add_u.age_add;
+ s->session->time = (long)time(NULL);
+ if (s->s3->alpn_selected != NULL) {
+ OPENSSL_free(s->session->ext.alpn_selected);
+ s->session->ext.alpn_selected =
+ OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len);
+ if (s->session->ext.alpn_selected == NULL) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ s->session->ext.alpn_selected_len = s->s3->alpn_selected_len;
+ }
+ s->session->ext.max_early_data = s->max_early_data;
}
/* get session encoding length */
@@ -3385,13 +3424,13 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
* long
*/
if (slen_full == 0 || slen_full > 0xFF00) {
- ossl_statem_set_error(s);
- return 0;
+ SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
+ goto err;
}
senc = OPENSSL_malloc(slen_full);
if (senc == NULL) {
- ossl_statem_set_error(s);
- return 0;
+ SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+ goto err;
}
ctx = EVP_CIPHER_CTX_new();
@@ -3470,11 +3509,14 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
}
/*
- * Ticket lifetime hint (advisory only): We leave this unspecified
- * for resumed session (for simplicity), and guess that tickets for
- * new sessions will live as long as their sessions.
+ * Ticket lifetime hint: For TLSv1.2 this is advisory only and we leave this
+ * unspecified for resumed session (for simplicity).
+ * In TLSv1.3 we reset the "time" field above, and always specify the
+ * timeout.
*/
- if (!WPACKET_put_bytes_u32(pkt, s->hit ? 0 : s->session->timeout)
+ if (!WPACKET_put_bytes_u32(pkt,
+ (s->hit && !SSL_IS_TLS13(s))
+ ? 0 : s->session->timeout)
|| (SSL_IS_TLS13(s)
&& !WPACKET_put_bytes_u32(pkt, age_add_u.age_add))
/* Now the actual ticket data */
@@ -3517,6 +3559,7 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
return 1;
err:
+ ossl_statem_set_error(s);
OPENSSL_free(senc);
EVP_CIPHER_CTX_free(ctx);
HMAC_CTX_free(hctx);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 4158548..2969b88 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -483,13 +483,7 @@ size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen,
int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
size_t len, size_t *secret_size)
{
- /*
- * TODO(TLS1.3): We haven't implemented TLS1.3 key derivation yet. For now
- * we will just force no use of EMS (which adds complications around the
- * handshake hash). This will need to be removed later
- */
- if ((s->session->flags & SSL_SESS_FLAG_EXTMS)
- && !SSL_IS_TLS13(s)) {
+ if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
unsigned char hash[EVP_MAX_MD_SIZE * 2];
size_t hashlen;
/*
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index e99a2ce..5cfaacd 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -475,7 +475,9 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
{TLSEXT_TYPE_signed_certificate_timestamp, "signed_certificate_timestamps"},
{TLSEXT_TYPE_padding, "padding"},
{TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
- {TLSEXT_TYPE_extended_master_secret, "extended_master_secret"}
+ {TLSEXT_TYPE_extended_master_secret, "extended_master_secret"},
+ {TLSEXT_TYPE_early_data_info, "ticket_early_data_info"},
+ {TLSEXT_TYPE_early_data, "early_data"}
};
static ssl_trace_tbl ssl_groups_tbl[] = {
@@ -680,6 +682,7 @@ static int ssl_print_extension(BIO *bio, int indent, int server,
{
size_t xlen, share_len;
unsigned int sigalg;
+ uint32_t max_early_data;
BIO_indent(bio, indent, 80);
BIO_printf(bio, "extension_type=%s(%d), length=%d\n",
@@ -830,6 +833,15 @@ static int ssl_print_extension(BIO *bio, int indent, int server,
return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1,
ssl_psk_kex_modes_tbl);
+ case TLSEXT_TYPE_early_data_info:
+ if (extlen != 4)
+ return 0;
+ max_early_data = (ext[0] << 24) | (ext[1] << 16) | (ext[2] << 8)
+ | ext[3];
+ BIO_indent(bio, indent + 2, 80);
+ BIO_printf(bio, "max_early_data=%u\n", max_early_data);
+ break;
+
default:
BIO_dump_indent(bio, (const char *)ext, extlen, indent + 2);
}
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
index 6faa4e0..47d23bd 100644
--- a/ssl/tls13_enc.c
+++ b/ssl/tls13_enc.c
@@ -56,6 +56,7 @@ int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret,
|| !WPACKET_sub_memcpy_u8(&pkt, hash, (hash == NULL) ? 0 : hashlen)
|| !WPACKET_get_total_written(&pkt, &hkdflabellen)
|| !WPACKET_finish(&pkt)) {
+ EVP_PKEY_CTX_free(pctx);
WPACKET_cleanup(&pkt);
return 0;
}
@@ -77,26 +78,26 @@ int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret,
* Given a |secret| generate a |key| of length |keylen| bytes. Returns 1 on
* success 0 on failure.
*/
-int tls13_derive_key(SSL *s, const unsigned char *secret, unsigned char *key,
- size_t keylen)
+int tls13_derive_key(SSL *s, const EVP_MD *md, const unsigned char *secret,
+ unsigned char *key, size_t keylen)
{
static const unsigned char keylabel[] = "key";
- return tls13_hkdf_expand(s, ssl_handshake_md(s), secret, keylabel,
- sizeof(keylabel) - 1, NULL, key, keylen);
+ return tls13_hkdf_expand(s, md, secret, keylabel, sizeof(keylabel) - 1,
+ NULL, key, keylen);
}
/*
* Given a |secret| generate an |iv| of length |ivlen| bytes. Returns 1 on
* success 0 on failure.
*/
-int tls13_derive_iv(SSL *s, const unsigned char *secret, unsigned char *iv,
- size_t ivlen)
+int tls13_derive_iv(SSL *s, const EVP_MD *md, const unsigned char *secret,
+ unsigned char *iv, size_t ivlen)
{
static const unsigned char ivlabel[] = "iv";
- return tls13_hkdf_expand(s, ssl_handshake_md(s), secret, ivlabel,
- sizeof(ivlabel) - 1, NULL, iv, ivlen);
+ return tls13_hkdf_expand(s, md, secret, ivlabel, sizeof(ivlabel) - 1,
+ NULL, iv, ivlen);
}
int tls13_derive_finishedkey(SSL *s, const EVP_MD *md,
@@ -242,7 +243,8 @@ int tls13_setup_key_block(SSL *s)
return 1;
}
-static int derive_secret_key_and_iv(SSL *s, int send,
+static int derive_secret_key_and_iv(SSL *s, int send, const EVP_MD *md,
+ const EVP_CIPHER *ciph,
const unsigned char *insecret,
const unsigned char *hash,
const unsigned char *label,
@@ -251,9 +253,7 @@ static int derive_secret_key_and_iv(SSL *s, int send,
{
unsigned char key[EVP_MAX_KEY_LENGTH];
size_t ivlen, keylen, taglen;
- const EVP_MD *md = ssl_handshake_md(s);
size_t hashlen = EVP_MD_size(md);
- const EVP_CIPHER *ciph = s->s3->tmp.new_sym_enc;
if (!tls13_hkdf_expand(s, md, insecret, label, labellen, hash, secret,
hashlen)) {
@@ -264,9 +264,16 @@ static int derive_secret_key_and_iv(SSL *s, int send,
/* TODO(size_t): convert me */
keylen = EVP_CIPHER_key_length(ciph);
if (EVP_CIPHER_mode(ciph) == EVP_CIPH_CCM_MODE) {
+ uint32_t algenc;
+
ivlen = EVP_CCM_TLS_IV_LEN;
- if (s->s3->tmp.new_cipher->algorithm_enc
- & (SSL_AES128CCM8 | SSL_AES256CCM8))
+ if (s->s3->tmp.new_cipher == NULL) {
+ /* We've not selected a cipher yet - we must be doing early data */
+ algenc = s->session->cipher->algorithm_enc;
+ } else {
+ algenc = s->s3->tmp.new_cipher->algorithm_enc;
+ }
+ if (algenc & (SSL_AES128CCM8 | SSL_AES256CCM8))
taglen = EVP_CCM8_TLS_TAG_LEN;
else
taglen = EVP_CCM_TLS_TAG_LEN;
@@ -275,8 +282,8 @@ static int derive_secret_key_and_iv(SSL *s, int send,
taglen = 0;
}
- if (!tls13_derive_key(s, secret, key, keylen)
- || !tls13_derive_iv(s, secret, iv, ivlen)) {
+ if (!tls13_derive_key(s, md, secret, key, keylen)
+ || !tls13_derive_iv(s, md, secret, iv, ivlen)) {
SSLerr(SSL_F_DERIVE_SECRET_KEY_AND_IV, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -312,6 +319,8 @@ static int derive_secret_key_and_iv(SSL *s, int send,
int tls13_change_cipher_state(SSL *s, int which)
{
+ static const unsigned char client_early_traffic[] =
+ "client early traffic secret";
static const unsigned char client_handshake_traffic[] =
"client handshake traffic secret";
static const unsigned char client_application_traffic[] =
@@ -334,6 +343,8 @@ int tls13_change_cipher_state(SSL *s, int which)
const unsigned char *label;
size_t labellen, hashlen = 0;
int ret = 0;
+ const EVP_MD *md;
+ const EVP_CIPHER *cipher;
if (which & SSL3_CC_READ) {
if (s->enc_read_ctx != NULL) {
@@ -367,13 +378,67 @@ int tls13_change_cipher_state(SSL *s, int which)
if (((which & SSL3_CC_CLIENT) && (which & SSL3_CC_WRITE))
|| ((which & SSL3_CC_SERVER) && (which & SSL3_CC_READ))) {
- if (which & SSL3_CC_HANDSHAKE) {
+ if (which & SSL3_CC_EARLY) {
+ EVP_MD_CTX *mdctx = NULL;
+ long handlen;
+ void *hdata;
+ unsigned int hashlenui;
+ const SSL_CIPHER *sslcipher = SSL_SESSION_get0_cipher(s->session);
+
+ insecret = s->early_secret;
+ label = client_early_traffic;
+ labellen = sizeof(client_early_traffic) - 1;
+ log_label = CLIENT_EARLY_LABEL;
+
+ handlen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+ if (handlen <= 0) {
+ SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE,
+ SSL_R_BAD_HANDSHAKE_LENGTH);
+ goto err;
+ }
+ if (sslcipher == NULL) {
+ SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /*
+ * We need to calculate the handshake digest using the digest from
+ * the session. We haven't yet selected our ciphersuite so we can't
+ * use ssl_handshake_md().
+ */
+ mdctx = EVP_MD_CTX_new();
+ if (mdctx == NULL) {
+ SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ cipher = EVP_get_cipherbynid(SSL_CIPHER_get_cipher_nid(sslcipher));
+ md = ssl_md(sslcipher->algorithm2);
+ if (md == NULL || !EVP_DigestInit_ex(mdctx, md, NULL)
+ || !EVP_DigestUpdate(mdctx, hdata, handlen)
+ || !EVP_DigestFinal_ex(mdctx, hashval, &hashlenui)) {
+ SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ EVP_MD_CTX_free(mdctx);
+ goto err;
+ }
+ hashlen = hashlenui;
+ EVP_MD_CTX_free(mdctx);
+ } else if (which & SSL3_CC_HANDSHAKE) {
insecret = s->handshake_secret;
finsecret = s->client_finished_secret;
finsecretlen = EVP_MD_size(ssl_handshake_md(s));
label = client_handshake_traffic;
labellen = sizeof(client_handshake_traffic) - 1;
log_label = CLIENT_HANDSHAKE_LABEL;
+ /*
+ * The hanshake hash used for the server read/client write handshake
+ * traffic secret is the same as the hash for the server
+ * write/client read handshake traffic secret. However, if we
+ * processed early data then we delay changing the server
+ * read/client write cipher state until later, and the handshake
+ * hashes have moved on. Therefore we use the value saved earlier
+ * when we did the server write/client read change cipher state.
+ */
+ hash = s->handshake_traffic_hash;
} else {
insecret = s->master_secret;
label = client_application_traffic;
@@ -388,6 +453,7 @@ int tls13_change_cipher_state(SSL *s, int which)
hash = s->server_finished_hash;
}
} else {
+ /* Early data never applies to client-read/server-write */
if (which & SSL3_CC_HANDSHAKE) {
insecret = s->handshake_secret;
finsecret = s->server_finished_secret;
@@ -403,10 +469,14 @@ int tls13_change_cipher_state(SSL *s, int which)
}
}
- if (!ssl3_digest_cached_records(s, 1)
- || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
- SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
- goto err;
+ if (!(which & SSL3_CC_EARLY)) {
+ md = ssl_handshake_md(s);
+ cipher = s->s3->tmp.new_sym_enc;
+ if (!ssl3_digest_cached_records(s, 1)
+ || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
+ SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
}
/*
@@ -416,6 +486,9 @@ int tls13_change_cipher_state(SSL *s, int which)
if (label == server_application_traffic)
memcpy(s->server_finished_hash, hashval, hashlen);
+ if (label == server_handshake_traffic)
+ memcpy(s->handshake_traffic_hash, hashval, hashlen);
+
if (label == client_application_traffic) {
/*
* We also create the resumption master secret, but this time use the
@@ -431,8 +504,9 @@ int tls13_change_cipher_state(SSL *s, int which)
s->session->master_key_length = hashlen;
}
- if (!derive_secret_key_and_iv(s, which & SSL3_CC_WRITE, insecret, hash,
- label, labellen, secret, iv, ciph_ctx)) {
+ if (!derive_secret_key_and_iv(s, which & SSL3_CC_WRITE, md, cipher,
+ insecret, hash, label, labellen, secret, iv,
+ ciph_ctx)) {
goto err;
}
@@ -485,7 +559,9 @@ int tls13_update_key(SSL *s, int send)
RECORD_LAYER_reset_read_sequence(&s->rlayer);
}
- if (!derive_secret_key_and_iv(s, send, insecret, NULL, application_traffic,
+ if (!derive_secret_key_and_iv(s, send, ssl_handshake_md(s),
+ s->s3->tmp.new_sym_enc, insecret, NULL,
+ application_traffic,
sizeof(application_traffic) - 1, secret, iv,
ciph_ctx))
goto err;
@@ -500,7 +576,7 @@ int tls13_update_key(SSL *s, int send)
int tls13_alert_code(int code)
{
- if (code == SSL_AD_MISSING_EXTENSION)
+ if (code == SSL_AD_MISSING_EXTENSION || code == SSL_AD_END_OF_EARLY_DATA)
return code;
return tls1_alert_code(code);
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 4b5e8c0..1b96527 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -1537,6 +1537,652 @@ static int test_set_sigalgs(int idx)
return testresult;
}
+#ifndef OPENSSL_NO_TLS1_3
+
+#define MSG1 "Hello"
+#define MSG2 "World."
+#define MSG3 "This"
+#define MSG4 "is"
+#define MSG5 "a"
+#define MSG6 "test."
+
+/*
+ * Helper method to setup objects for early data test. Caller frees objects on
+ * error.
+ */
+static int setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, SSL **clientssl,
+ SSL **serverssl, SSL_SESSION **sess)
+{
+ if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), sctx,
+ cctx, cert, privkey)) {
+ printf("Unable to create SSL_CTX pair\n");
+ return 0;
+ }
+
+ if (!create_ssl_objects(*sctx, *cctx, serverssl, clientssl, NULL, NULL)) {
+ printf("Unable to create SSL objects\n");
+ return 0;
+ }
+
+ if (!create_ssl_connection(*serverssl, *clientssl, SSL_ERROR_NONE)) {
+ printf("Unable to create SSL connection\n");
+ return 0;
+ }
+
+ *sess = SSL_get1_session(*clientssl);
+
+ SSL_shutdown(*clientssl);
+ SSL_shutdown(*serverssl);
+
+ SSL_free(*serverssl);
+ SSL_free(*clientssl);
+ *serverssl = *clientssl = NULL;
+
+ if (!create_ssl_objects(*sctx, *cctx, serverssl, clientssl, NULL, NULL)) {
+ printf("Unable to create SSL objects (2)\n");
+ return 0;
+ }
+
+ if (!SSL_set_session(*clientssl, *sess)) {
+ printf("Failed setting session\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_early_data_read_write(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess = NULL;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ if (!setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess))
+ goto end;
+
+ /* Write and read some early data */
+ if (!SSL_write_early_data(clientssl, MSG1, strlen(MSG1), &written)
+ || written != strlen(MSG1)) {
+ printf("Failed writing early data message 1\n");
+ goto end;
+ }
+
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_SUCCESS
+ || readbytes != strlen(MSG1)
+ || memcmp(MSG1, buf, strlen(MSG1))) {
+ printf("Failed reading early data message 1\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_ACCEPTED) {
+ printf("Unexpected early data status\n");
+ goto end;
+ }
+
+ /*
+ * Server should be able to write data, and client should be able to
+ * read it.
+ */
+ if (!SSL_write_early_data(serverssl, MSG2, strlen(MSG2), &written)
+ || written != strlen(MSG2)) {
+ printf("Failed writing message 2\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG2)
+ || memcmp(MSG2, buf, strlen(MSG2))) {
+ printf("Failed reading message 2\n");
+ goto end;
+ }
+
+ /* Even after reading normal data, client should be able write early data */
+ if (!SSL_write_early_data(clientssl, MSG3, strlen(MSG3), &written)
+ || written != strlen(MSG3)) {
+ printf("Failed writing early data message 3\n");
+ goto end;
+ }
+
+ /* 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)
+ || memcmp(MSG3, buf, strlen(MSG3))) {
+ printf("Failed reading early data message 3\n");
+ goto end;
+ }
+
+ /* 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;
+ }
+
+ if (!SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG4)
+ || memcmp(MSG4, buf, strlen(MSG4))) {
+ printf("Failed reading message 4\n");
+ goto end;
+ }
+
+ /*
+ * If client writes normal data it should mean writing early data is no
+ * longer possible.
+ */
+ if (!SSL_write_ex(clientssl, MSG5, strlen(MSG5), &written)
+ || written != strlen(MSG5)) {
+ printf("Failed writing message 5\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_ACCEPTED) {
+ printf("Unexpected early data status(2)\n");
+ goto end;
+ }
+
+ /* Server should be told that there is no more early data */
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_FINISH
+ || readbytes != 0) {
+ printf("Failed finishing read of early data\n");
+ goto end;
+ }
+
+ /* Server should be able to read normal data */
+ if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG5)) {
+ printf("Failed reading message 5\n");
+ goto end;
+ }
+
+ /* 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;
+ }
+ ERR_clear_error();
+
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_ERROR) {
+ printf("Unexpected success reading early data\n");
+ goto end;
+ }
+ ERR_clear_error();
+
+ /*
+ * Make sure we process the NewSessionTicket. This arrives post-handshake
+ * so we must make sure we attempt a read - even though we don't expect to
+ * actually get any application data.
+ */
+ if (SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)) {
+ printf("Unexpected success doing final client read\n");
+ goto end;
+ }
+
+ SSL_SESSION_free(sess);
+ sess = SSL_get1_session(clientssl);
+
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+ printf("Unable to create SSL objects (3)\n");
+ goto end;
+ }
+
+ if (!SSL_set_session(clientssl, sess)) {
+ printf("Failed setting session (2)\n");
+ goto end;
+ }
+
+ /* Write and read some early data */
+ if (!SSL_write_early_data(clientssl, MSG1, strlen(MSG1), &written)
+ || written != strlen(MSG1)) {
+ printf("Failed writing early data message 1\n");
+ goto end;
+ }
+
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_SUCCESS
+ || readbytes != strlen(MSG1)
+ || memcmp(MSG1, buf, strlen(MSG1))) {
+ printf("Failed reading early data message 1\n");
+ goto end;
+ }
+
+ if (SSL_connect(clientssl) <= 0) {
+ printf("Unable to complete client handshake\n");
+ goto end;
+ }
+
+ /*
+ * We expect SSL_accept() to initially block as it handles the end of early
+ * data alert
+ */
+ if (SSL_accept(serverssl) > 0) {
+ printf("Unexpected success completing server handshake\n");
+ goto end;
+ }
+
+ if (SSL_accept(serverssl) <= 0) {
+ printf("Unable to complete server handshake\n");
+ goto end;
+ }
+
+ /* 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;
+ }
+ ERR_clear_error();
+
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_ERROR) {
+ printf("Unexpected success reading early data (2)\n");
+ goto end;
+ }
+ ERR_clear_error();
+
+ /* Client and server should be able to write/read normal data */
+ if (!SSL_write_ex(clientssl, MSG5, strlen(MSG5), &written)
+ || written != strlen(MSG5)) {
+ printf("Failed writing message 5 (2)\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG5)) {
+ printf("Failed reading message 5 (2)\n");
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ if(!testresult)
+ ERR_print_errors_fp(stdout);
+ SSL_SESSION_free(sess);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+static int test_early_data_skip(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ /*
+ * Test that a server attempting to read early data can handle a connection
+ * from a client where the early data is not acceptable.
+ */
+
+ if (!setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess))
+ goto end;
+
+ /*
+ * Deliberately corrupt the creation time. We take 20 seconds off the time.
+ * It could be any value as long as it is not within tolerance. This should
+ * mean the ticket is rejected.
+ */
+ if (!SSL_SESSION_set_time(sess, time(NULL) - 20)) {
+ printf("Unexpected failure setting session creation time\n");
+ goto end;
+ }
+
+ /* Write some early data */
+ if (!SSL_write_early_data(clientssl, MSG1, strlen(MSG1), &written)
+ || written != strlen(MSG1)) {
+ printf("Failed writing early data message 1\n");
+ goto end;
+ }
+
+ /* Server should reject the early data and skip over it */
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_FINISH
+ || readbytes != 0) {
+ printf("Failed reading early data\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_REJECTED) {
+ printf("Unexpected early data status\n");
+ goto end;
+ }
+
+ /*
+ * We should be able to send normal data despite rejection of early data
+ */
+ if (!SSL_write_ex(clientssl, MSG2, strlen(MSG2), &written)
+ || written != strlen(MSG2)) {
+ printf("Failed writing message 2\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_REJECTED) {
+ printf("Unexpected early data status (2)\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG2)
+ || memcmp(MSG2, buf, strlen(MSG2))) {
+ printf("Failed reading message 2\n");
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ if(!testresult)
+ ERR_print_errors_fp(stdout);
+ SSL_SESSION_free(sess);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+static int test_early_data_not_sent(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ /*
+ * Test that a server attempting to read early data can handle a connection
+ * from a client that doesn't send any.
+ */
+
+ if (!setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess))
+ goto end;
+
+ /* Write some data - should block due to handshake with server */
+ SSL_set_connect_state(clientssl);
+ if (SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)) {
+ printf("Unexpected success writing message 1\n");
+ goto end;
+ }
+
+ /* Server should detect that early data has not been sent */
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_FINISH
+ || readbytes != 0) {
+ printf("Failed reading early data\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_NOT_SENT) {
+ printf("Unexpected early data status\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_NOT_SENT) {
+ printf("Unexpected early data status (2)\n");
+ goto end;
+ }
+
+ /* Continue writing the message we started earlier */
+ if (!SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)
+ || written != strlen(MSG1)) {
+ printf("Failed writing message 1\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG1)
+ || memcmp(MSG1, buf, strlen(MSG1))) {
+ printf("Failed reading message 1\n");
+ goto end;
+ }
+
+ if (!SSL_write_ex(serverssl, MSG2, strlen(MSG2), &written)
+ || written != strlen(MSG2)) {
+ printf("Failed writing message 2\n");
+ goto end;
+ }
+
+ /* Should block due to the NewSessionTicket arrival */
+ if (SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)) {
+ printf("Unexpected success reading message 2\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG2)
+ || memcmp(MSG2, buf, strlen(MSG2))) {
+ printf("Failed reading message 2\n");
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ if(!testresult)
+ ERR_print_errors_fp(stdout);
+ SSL_SESSION_free(sess);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+static int test_early_data_not_expected(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ /*
+ * Test that a server that doesn't try to read early data can handle a
+ * client sending some.
+ */
+
+ if (!setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess))
+ goto end;
+
+ /* Write some early data */
+ if (!SSL_write_early_data(clientssl, MSG1, strlen(MSG1), &written)) {
+ printf("Unexpected failure writing message 1\n");
+ goto end;
+ }
+
+ /*
+ * Server should skip over early data and then block waiting for client to
+ * continue handshake
+ */
+ if (SSL_accept(serverssl) > 0) {
+ printf("Unexpected success setting up server connection\n");
+ goto end;
+ }
+
+ if (SSL_connect(clientssl) <= 0) {
+ printf("Failed setting up client connection\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_REJECTED) {
+ printf("Unexpected early data status\n");
+ goto end;
+ }
+
+ if (SSL_accept(serverssl) <= 0) {
+ printf("Failed setting up server connection\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_REJECTED) {
+ printf("Unexpected early data status (2)\n");
+ goto end;
+ }
+
+ /* Send some normal data from client to server */
+ if (!SSL_write_ex(clientssl, MSG2, strlen(MSG2), &written)
+ || written != strlen(MSG2)) {
+ printf("Failed writing message 2\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG2)
+ || memcmp(MSG2, buf, strlen(MSG2))) {
+ printf("Failed reading message 2\n");
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ if(!testresult)
+ ERR_print_errors_fp(stdout);
+ SSL_SESSION_free(sess);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+
+# ifndef OPENSSL_NO_TLS1_2
+static int test_early_data_tls1_2(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ /*
+ * Test that a server attempting to read early data can handle a connection
+ * from a TLSv1.2 client.
+ */
+
+ if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
+ &cctx, cert, privkey)) {
+ printf("Unable to create SSL_CTX pair\n");
+ goto end;
+ }
+
+ if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+ printf("Unable to create SSL objects\n");
+ goto end;
+ }
+
+ /* Write some data - should block due to handshake with server */
+ SSL_set_max_proto_version(clientssl, TLS1_2_VERSION);
+ SSL_set_connect_state(clientssl);
+ if (SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)) {
+ printf("Unexpected success writing message 1\n");
+ goto end;
+ }
+
+ /*
+ * Server should do TLSv1.2 handshake. First it will block waiting for more
+ * messages from client after ServerDone. Then SSL_read_early_data should
+ * finish and detect that early data has not been sent
+ */
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_ERROR) {
+ printf("Unexpected success reading early data\n");
+ goto end;
+ }
+
+ /*
+ * Continue writing the message we started earlier. Will still block waiting
+ * for the CCS/Finished from server
+ */
+ if (SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)) {
+ printf("Unexpected success writing message 1\n");
+ goto end;
+ }
+
+ if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
+ != SSL_READ_EARLY_DATA_FINISH
+ || readbytes != 0) {
+ printf("Failed reading early data\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_NOT_SENT) {
+ printf("Unexpected early data status\n");
+ goto end;
+ }
+
+ /* Continue writing the message we started earlier */
+ if (!SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)
+ || written != strlen(MSG1)) {
+ printf("Failed writing message 1\n");
+ goto end;
+ }
+
+ if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_NOT_SENT) {
+ printf("Unexpected early data status (2)\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG1)
+ || memcmp(MSG1, buf, strlen(MSG1))) {
+ printf("Failed reading message 1\n");
+ goto end;
+ }
+
+ if (!SSL_write_ex(serverssl, MSG2, strlen(MSG2), &written)
+ || written != strlen(MSG2)) {
+ printf("Failed writing message 2\n");
+ goto end;
+ }
+
+ if (!SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
+ || readbytes != strlen(MSG2)
+ || memcmp(MSG2, buf, strlen(MSG2))) {
+ printf("Failed reading message 2\n");
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ if(!testresult)
+ ERR_print_errors_fp(stdout);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+# endif
+#endif
+
int test_main(int argc, char *argv[])
{
int testresult = 1;
@@ -1573,6 +2219,15 @@ int test_main(int argc, char *argv[])
#ifndef OPENSSL_NO_TLS1_2
ADD_TEST(test_early_cb);
#endif
+#ifndef OPENSSL_NO_TLS1_3
+ ADD_TEST(test_early_data_read_write);
+ ADD_TEST(test_early_data_skip);
+ ADD_TEST(test_early_data_not_sent);
+ ADD_TEST(test_early_data_not_expected);
+# ifndef OPENSSL_NO_TLS1_2
+ ADD_TEST(test_early_data_tls1_2);
+# endif
+#endif
testresult = run_tests(argv[0]);
diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c
index 7f177bf..55424b1 100644
--- a/test/tls13secretstest.c
+++ b/test/tls13secretstest.c
@@ -192,6 +192,11 @@ int ssl_log_secret(SSL *ssl,
return 1;
}
+const EVP_MD *ssl_md(int idx)
+{
+ return EVP_sha256();
+}
+
/* End of mocked out code */
static int test_secret(SSL *s, unsigned char *prk,
@@ -222,7 +227,7 @@ static int test_secret(SSL *s, unsigned char *prk,
return 0;
}
- if (!tls13_derive_key(s, gensecret, key, KEYLEN)) {
+ if (!tls13_derive_key(s, md, gensecret, key, KEYLEN)) {
fprintf(stderr, "Key generation failed\n");
return 0;
}
@@ -232,7 +237,7 @@ static int test_secret(SSL *s, unsigned char *prk,
return 0;
}
- if (!tls13_derive_iv(s, gensecret, iv, IVLEN)) {
+ if (!tls13_derive_iv(s, md, gensecret, iv, IVLEN)) {
fprintf(stderr, "IV generation failed\n");
return 0;
}
diff --git a/util/libssl.num b/util/libssl.num
index 20642ce..3c024e4 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -424,3 +424,11 @@ SSL_early_get0_random 424 1_1_1 EXIST::FUNCTION:
SSL_CTX_set_early_cb 425 1_1_1 EXIST::FUNCTION:
SSL_early_get0_legacy_version 426 1_1_1 EXIST::FUNCTION:
SSL_early_isv2 427 1_1_1 EXIST::FUNCTION:
+SSL_set_max_early_data 428 1_1_1 EXIST::FUNCTION:
+SSL_CTX_set_max_early_data 429 1_1_1 EXIST::FUNCTION:
+SSL_get_max_early_data 430 1_1_1 EXIST::FUNCTION:
+SSL_CTX_get_max_early_data 431 1_1_1 EXIST::FUNCTION:
+SSL_write_early_data 432 1_1_1 EXIST::FUNCTION:
+SSL_read_early_data 433 1_1_1 EXIST::FUNCTION:
+SSL_get_early_data_status 434 1_1_1 EXIST::FUNCTION:
+SSL_SESSION_get_max_early_data 435 1_1_1 EXIST::FUNCTION:
More information about the openssl-commits
mailing list