The branch master has been updated via 0ababfec93337a1fb8160a75df3ccc227faa72d4 (commit) via 091ecfad6e3f157a875f0dec2d913c0c992bf1d9 (commit) via 0ca3aea7d359144681d591eb53961ec915c8de8e (commit) via 758e05c52ec5acb133647e69495812269ad67525 (commit) via 318d3c0e62d0de511b8721e087278a6c70db8b92 (commit) via 75259b4346a1a786b4a23987123b18b674327b8d (commit) via 5cc807da2571c52cc7c1c87197a81963def7ee3a (commit) via 7b0a3ce0f9f54cf7b527fe57d98748a7aaa571bd (commit) via 426dfc9ff7c1afaf1ed5981a9c7846e310c7ae3e (commit) via e7dd763e513f576b8e4e32bb5d08abc37bb08a40 (commit) via be60b10a80663d7af6e87d53f908e58d63c54d95 (commit) via fc7129dc37f38022382338cf37cee795d975450f (commit) via 6f40214f68d06820304e6f9a4c60099a1fbce10c (commit) via 597c51bc980ba6d7470dd8de747ac12a6c7a442b (commit) via db37d32cb89160328b0ba48e3808f601a7b3ebe8 (commit) via 066904cceef26bbb5c63c237d20829fb0db82ddc (commit) via 4d02f8706381bf2bd002951daef9b26d9ed85968 (commit) via fa9f9350f3d22168ebc53b72ad042b714e4cb691 (commit) via fdd9236747d7b843f1f5644b3e95580b80d9a598 (commit) via 2d729db2f0c047e64c580342f6fba0d99b2ada50 (commit) via a5816a5ab99610201dcec57a0e02b883d9d32891 (commit) via 88050dd1960bfaba7ede12a3ce1afe40f5deb124 (commit) via 86b165e39fa94d4eceb9bb1611350b949fea7cc9 (commit) from f90852093f149ae942a77c2c27d2a61888cff8e9 (commit)
- Log ----------------------------------------------------------------- commit 0ababfec93337a1fb8160a75df3ccc227faa72d4 Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 17:55:34 2017 +0000 Fix some clang compilation errors Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 091ecfad6e3f157a875f0dec2d913c0c992bf1d9 Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 17:55:06 2017 +0000 Don't run the TLSv1.3 CCS tests if TLSv1.3 is not enabled Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 0ca3aea7d359144681d591eb53961ec915c8de8e Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 10:13:13 2017 +0000 Add some TLSv1.3 CCS tests Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 758e05c52ec5acb133647e69495812269ad67525 Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 15:49:08 2017 +0000 Make sure we treat records written after HRR as TLSv1.3 This fixes a bug where some CCS records were written with the wrong TLS record version. Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 318d3c0e62d0de511b8721e087278a6c70db8b92 Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 14:33:22 2017 +0000 Issue a CCS from the client if we received an HRR Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 75259b4346a1a786b4a23987123b18b674327b8d Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 14:29:28 2017 +0000 Fix server side HRR flushing Flush following the CCS after an HRR. Only flush the HRR if middlebox compat is turned off. Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 5cc807da2571c52cc7c1c87197a81963def7ee3a Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 30 11:28:26 2017 +0000 Delay flush until after CCS with early_data Normally we flush immediately after writing the ClientHello. However if we are going to write a CCS immediately because we've got early_data to come, then we should move the flush until after the CCS. Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 7b0a3ce0f9f54cf7b527fe57d98748a7aaa571bd Author: Matt Caswell <m...@openssl.org> Date: Mon Nov 13 16:12:35 2017 +0000 Ensure CCS sent before early_data has the correct record version Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 426dfc9ff7c1afaf1ed5981a9c7846e310c7ae3e Author: Matt Caswell <m...@openssl.org> Date: Tue Dec 5 10:16:25 2017 +0000 Send supported_versions in an HRR Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit e7dd763e513f576b8e4e32bb5d08abc37bb08a40 Author: Matt Caswell <m...@openssl.org> Date: Mon Nov 13 15:01:07 2017 +0000 Make sure supported_versions appears in an HRR too Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit be60b10a80663d7af6e87d53f908e58d63c54d95 Author: Matt Caswell <m...@openssl.org> Date: Mon Nov 13 14:40:46 2017 +0000 Update TLSProxy to know about new HRR style Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit fc7129dc37f38022382338cf37cee795d975450f Author: Matt Caswell <m...@openssl.org> Date: Mon Nov 13 11:24:51 2017 +0000 Update state machine to send CCS based on whether we did an HRR The CCS may be sent at different times based on whether or not we sent an HRR earlier. In order to make that decision this commit also updates things to make sure we remember whether an HRR was used or not. Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 6f40214f68d06820304e6f9a4c60099a1fbce10c Author: Matt Caswell <m...@openssl.org> Date: Thu Nov 9 16:03:40 2017 +0000 Fix an HRR bug Ensure that after an HRR we can only negotiate TLSv1.3 Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 597c51bc980ba6d7470dd8de747ac12a6c7a442b Author: Matt Caswell <m...@openssl.org> Date: Tue Dec 5 10:14:35 2017 +0000 Merge HRR into ServerHello Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit db37d32cb89160328b0ba48e3808f601a7b3ebe8 Author: Matt Caswell <m...@openssl.org> Date: Wed Nov 8 15:00:48 2017 +0000 Send a CCS after ServerHello in TLSv1.3 if using middlebox compat mode Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 066904cceef26bbb5c63c237d20829fb0db82ddc Author: Matt Caswell <m...@openssl.org> Date: Wed Nov 8 14:26:48 2017 +0000 Send a CCS from a client in an early_data handshake Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 4d02f8706381bf2bd002951daef9b26d9ed85968 Author: Matt Caswell <m...@openssl.org> Date: Wed Nov 8 11:37:12 2017 +0000 Send a CCS from the client in a non-early_data handshake Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit fa9f9350f3d22168ebc53b72ad042b714e4cb691 Author: Matt Caswell <m...@openssl.org> Date: Wed Nov 8 11:18:00 2017 +0000 Remove TLSv1.3 specific write transition for ClientHello Since we no longer do version negotiation during the processing of an HRR we do not need the TLSv1.3 specific write transition for ClientHello Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit fdd9236747d7b843f1f5644b3e95580b80d9a598 Author: Matt Caswell <m...@openssl.org> Date: Tue Nov 7 16:36:51 2017 +0000 Drop CCS messages received in the TLSv1.3 handshake Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 2d729db2f0c047e64c580342f6fba0d99b2ada50 Author: Matt Caswell <m...@openssl.org> Date: Tue Nov 7 16:04:35 2017 +0000 Send TLSv1.2 as the record version when using TLSv1.3 Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit a5816a5ab99610201dcec57a0e02b883d9d32891 Author: Matt Caswell <m...@openssl.org> Date: Tue Nov 7 10:45:43 2017 +0000 Implement session id TLSv1.3 middlebox compatibility mode Clients will send a "fake" session id and servers must echo it back. Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 88050dd1960bfaba7ede12a3ce1afe40f5deb124 Author: Matt Caswell <m...@openssl.org> Date: Fri Nov 3 16:38:48 2017 +0000 Update ServerHello to new draft-22 format The new ServerHello format is essentially now the same as the old TLSv1.2 one, but it must additionally include supported_versions. The version field is fixed at TLSv1.2, and the version negotiation happens solely via supported_versions. Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) commit 86b165e39fa94d4eceb9bb1611350b949fea7cc9 Author: Matt Caswell <m...@openssl.org> Date: Fri Nov 3 11:26:29 2017 +0000 Update the TLSv1.3 draft version indicators to draft 22 Reviewed-by: Ben Kaduk <ka...@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4701) ----------------------------------------------------------------------- Summary of changes: apps/apps.h | 8 +- apps/s_cb.c | 1 - crypto/err/openssl.txt | 8 + include/openssl/ssl.h | 10 +- include/openssl/ssl3.h | 1 - include/openssl/sslerr.h | 7 + include/openssl/tls1.h | 6 +- ssl/record/rec_layer_s3.c | 3 +- ssl/record/ssl3_record.c | 39 +- ssl/ssl_conf.c | 6 +- ssl/ssl_err.c | 12 + ssl/ssl_lib.c | 6 +- ssl/ssl_locl.h | 22 +- ssl/ssl_stat.c | 8 - ssl/statem/extensions.c | 60 ++- ssl/statem/extensions_clnt.c | 69 ++- ssl/statem/extensions_srvr.c | 25 +- ssl/statem/statem_clnt.c | 347 +++++++++------ ssl/statem/statem_lib.c | 116 +++-- ssl/statem/statem_locl.h | 9 + ssl/statem/statem_srvr.c | 164 +++---- ssl/t1_trce.c | 45 +- test/asynciotest.c | 42 +- test/build.info | 6 +- test/clienthellotest.c | 2 + test/recipes/70-test_key_share.t | 14 +- test/recipes/70-test_sslrecords.t | 3 +- test/recipes/70-test_sslversions.t | 4 +- test/recipes/70-test_tls13cookie.t | 2 +- test/recipes/70-test_tls13kexmodes.t | 8 +- test/recipes/70-test_tls13messages.t | 10 +- ...0-test_tls13encryption.t => 90-test_tls13ccs.t} | 10 +- test/tls13ccstest.c | 493 +++++++++++++++++++++ util/perl/TLSProxy/HelloRetryRequest.pm | 150 ------- util/perl/TLSProxy/Message.pm | 21 +- util/perl/TLSProxy/Proxy.pm | 1 - util/perl/TLSProxy/Record.pm | 28 +- util/perl/TLSProxy/ServerHello.pm | 58 +-- util/perl/checkhandshake.pm | 68 ++- 39 files changed, 1299 insertions(+), 593 deletions(-) copy test/recipes/{90-test_tls13encryption.t => 90-test_tls13ccs.t} (60%) create mode 100644 test/tls13ccstest.c delete mode 100644 util/perl/TLSProxy/HelloRetryRequest.pm diff --git a/apps/apps.h b/apps/apps.h index bb89eae..321f644 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -208,7 +208,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, OPT_S_STRICT, OPT_S_SIGALGS, OPT_S_CLIENTSIGALGS, OPT_S_GROUPS, \ OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, \ OPT_S_RECORD_PADDING, OPT_S_DEBUGBROKE, OPT_S_COMP, \ - OPT_S_NO_RENEGOTIATION, OPT_S__LAST + OPT_S_NO_RENEGOTIATION, OPT_S_NO_MIDDLEBOX, OPT_S__LAST # define OPT_S_OPTIONS \ {"no_ssl3", OPT_S_NOSSL3, '-',"Just disable SSLv3" }, \ @@ -253,7 +253,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, {"record_padding", OPT_S_RECORD_PADDING, 's', \ "Block size to pad TLS 1.3 records to."}, \ {"debug_broken_protocol", OPT_S_DEBUGBROKE, '-', \ - "Perform all sorts of protocol violations for testing purposes"} + "Perform all sorts of protocol violations for testing purposes"}, \ + {"no_middlebox", OPT_S_NO_MIDDLEBOX, '-', "Disable TLSv1.3 middlebox compat mode" } # define OPT_S_CASES \ @@ -283,7 +284,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, case OPT_S_CIPHER: \ case OPT_S_RECORD_PADDING: \ case OPT_S_NO_RENEGOTIATION: \ - case OPT_S_DEBUGBROKE + case OPT_S_DEBUGBROKE: \ + case OPT_S_NO_MIDDLEBOX #define IS_NO_PROT_FLAG(o) \ (o == OPT_S_NOSSL3 || o == OPT_S_NOTLS1 || o == OPT_S_NOTLS1_1 \ diff --git a/apps/s_cb.c b/apps/s_cb.c index 79d2919..c7c9ecb 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -525,7 +525,6 @@ static STRINT_PAIR handshakes[] = { {", HelloVerifyRequest", DTLS1_MT_HELLO_VERIFY_REQUEST}, {", NewSessionTicket", SSL3_MT_NEWSESSION_TICKET}, {", EndOfEarlyData", SSL3_MT_END_OF_EARLY_DATA}, - {", HelloRetryRequest", SSL3_MT_HELLO_RETRY_REQUEST}, {", EncryptedExtensions", SSL3_MT_ENCRYPTED_EXTENSIONS}, {", Certificate", SSL3_MT_CERTIFICATE}, {", ServerKeyExchange", SSL3_MT_SERVER_KEY_EXCHANGE}, diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 308abae..872016f 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1292,6 +1292,8 @@ SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET:460:tls_construct_stoc_session_ticket SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST:461:tls_construct_stoc_status_request SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS:544:\ tls_construct_stoc_supported_groups +SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS:608:\ + tls_construct_stoc_supported_versions SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP:462:tls_construct_stoc_use_srtp SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO:521:\ tls_early_post_process_client_hello @@ -1332,11 +1334,13 @@ SSL_F_TLS_PARSE_STOC_SCT:564:tls_parse_stoc_sct SSL_F_TLS_PARSE_STOC_SERVER_NAME:583:tls_parse_stoc_server_name SSL_F_TLS_PARSE_STOC_SESSION_TICKET:584:tls_parse_stoc_session_ticket SSL_F_TLS_PARSE_STOC_STATUS_REQUEST:585:tls_parse_stoc_status_request +SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS:609:tls_parse_stoc_supported_versions SSL_F_TLS_PARSE_STOC_USE_SRTP:446:tls_parse_stoc_use_srtp SSL_F_TLS_POST_PROCESS_CLIENT_HELLO:378:tls_post_process_client_hello SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE:384:\ tls_post_process_client_key_exchange SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE:360:tls_prepare_client_certificate +SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST:610:tls_process_as_hello_retry_request SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST:361:tls_process_certificate_request SSL_F_TLS_PROCESS_CERT_STATUS:362:* SSL_F_TLS_PROCESS_CERT_STATUS_BODY:495:tls_process_cert_status_body @@ -2357,6 +2361,7 @@ SSL_R_BAD_EXTENSION:110:bad extension SSL_R_BAD_HANDSHAKE_LENGTH:332:bad handshake length SSL_R_BAD_HANDSHAKE_STATE:236:bad handshake state SSL_R_BAD_HELLO_REQUEST:105:bad hello request +SSL_R_BAD_HRR_VERSION:263:bad hrr version SSL_R_BAD_KEY_SHARE:108:bad key share SSL_R_BAD_KEY_UPDATE:122:bad key update SSL_R_BAD_LENGTH:271:bad length @@ -2450,6 +2455,7 @@ SSL_R_INCONSISTENT_EARLY_DATA_SNI:231:inconsistent early data sni SSL_R_INCONSISTENT_EXTMS:104:inconsistent extms SSL_R_INSUFFICIENT_SECURITY:241:insufficient security SSL_R_INVALID_ALERT:205:invalid alert +SSL_R_INVALID_CCS_MESSAGE:260:invalid ccs message SSL_R_INVALID_CERTIFICATE_OR_ALG:238:invalid certificate or alg SSL_R_INVALID_COMMAND:280:invalid command SSL_R_INVALID_COMPRESSION_ALGORITHM:341:invalid compression algorithm @@ -2460,6 +2466,7 @@ SSL_R_INVALID_MAX_EARLY_DATA:174:invalid max early data SSL_R_INVALID_NULL_CMD_NAME:385:invalid null cmd name SSL_R_INVALID_SEQUENCE_NUMBER:402:invalid sequence number SSL_R_INVALID_SERVERINFO_DATA:388:invalid serverinfo data +SSL_R_INVALID_SESSION_ID:999:invalid session id SSL_R_INVALID_SRP_USERNAME:357:invalid srp username SSL_R_INVALID_STATUS_RESPONSE:328:invalid status response SSL_R_INVALID_TICKET_KEYS_LENGTH:325:invalid ticket keys length @@ -2579,6 +2586,7 @@ SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS:239:\ unable to find public key parameters SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES:242:unable to load ssl3 md5 routines SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES:243:unable to load ssl3 sha1 routines +SSL_R_UNEXPECTED_CCS_MESSAGE:262:unexpected ccs message SSL_R_UNEXPECTED_END_OF_EARLY_DATA:178:unexpected end of early data SSL_R_UNEXPECTED_MESSAGE:244:unexpected message SSL_R_UNEXPECTED_RECORD:245:unexpected record diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index a5251b5..98a106b 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -338,9 +338,17 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); # define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000U /* Disable encrypt-then-mac */ # define SSL_OP_NO_ENCRYPT_THEN_MAC 0x00080000U + +/* + * Enable TLSv1.3 Compatibility mode. This is on by default. A future version + * of OpenSSL may have this disabled by default. + */ +# define SSL_OP_ENABLE_MIDDLEBOX_COMPAT 0x00100000U + /* Prioritize Chacha20Poly1305 when client does. * Modifies SSL_OP_CIPHER_SERVER_PREFERENCE */ # define SSL_OP_PRIORITIZE_CHACHA 0x00200000U + /* * Set on servers to choose the cipher according to the server's preferences */ @@ -979,8 +987,6 @@ typedef enum { TLS_ST_CR_CERT_VRFY, TLS_ST_SW_CERT_VRFY, TLS_ST_CR_HELLO_REQ, - TLS_ST_SW_HELLO_RETRY_REQUEST, - TLS_ST_CR_HELLO_RETRY_REQUEST, TLS_ST_SW_KEY_UPDATE, TLS_ST_CW_KEY_UPDATE, TLS_ST_SR_KEY_UPDATE, diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index e9d56a8..b781f61 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -289,7 +289,6 @@ extern "C" { # define SSL3_MT_SERVER_HELLO 2 # define SSL3_MT_NEWSESSION_TICKET 4 # define SSL3_MT_END_OF_EARLY_DATA 5 -# define SSL3_MT_HELLO_RETRY_REQUEST 6 # define SSL3_MT_ENCRYPTED_EXTENSIONS 8 # define SSL3_MT_CERTIFICATE 11 # define SSL3_MT_SERVER_KEY_EXCHANGE 12 diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index b54459b..2986be8 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -340,6 +340,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET 460 # define SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST 461 # define SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS 544 +# define SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS 608 # define SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP 462 # define SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO 521 # define SSL_F_TLS_FINISH_HANDSHAKE 597 @@ -379,10 +380,12 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_STOC_SERVER_NAME 583 # define SSL_F_TLS_PARSE_STOC_SESSION_TICKET 584 # define SSL_F_TLS_PARSE_STOC_STATUS_REQUEST 585 +# define SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS 609 # define SSL_F_TLS_PARSE_STOC_USE_SRTP 446 # define SSL_F_TLS_POST_PROCESS_CLIENT_HELLO 378 # define SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE 384 # define SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE 360 +# define SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST 610 # define SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST 361 # define SSL_F_TLS_PROCESS_CERT_STATUS 362 # define SSL_F_TLS_PROCESS_CERT_STATUS_BODY 495 @@ -441,6 +444,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_BAD_HANDSHAKE_LENGTH 332 # define SSL_R_BAD_HANDSHAKE_STATE 236 # define SSL_R_BAD_HELLO_REQUEST 105 +# define SSL_R_BAD_HRR_VERSION 263 # define SSL_R_BAD_KEY_SHARE 108 # define SSL_R_BAD_KEY_UPDATE 122 # define SSL_R_BAD_LENGTH 271 @@ -531,6 +535,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_INCONSISTENT_EXTMS 104 # define SSL_R_INSUFFICIENT_SECURITY 241 # define SSL_R_INVALID_ALERT 205 +# define SSL_R_INVALID_CCS_MESSAGE 260 # define SSL_R_INVALID_CERTIFICATE_OR_ALG 238 # define SSL_R_INVALID_COMMAND 280 # define SSL_R_INVALID_COMPRESSION_ALGORITHM 341 @@ -541,6 +546,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_INVALID_NULL_CMD_NAME 385 # define SSL_R_INVALID_SEQUENCE_NUMBER 402 # define SSL_R_INVALID_SERVERINFO_DATA 388 +# define SSL_R_INVALID_SESSION_ID 999 # define SSL_R_INVALID_SRP_USERNAME 357 # define SSL_R_INVALID_STATUS_RESPONSE 328 # define SSL_R_INVALID_TICKET_KEYS_LENGTH 325 @@ -682,6 +688,7 @@ int ERR_load_SSL_strings(void); # 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_CCS_MESSAGE 262 # define SSL_R_UNEXPECTED_END_OF_EARLY_DATA 178 # define SSL_R_UNEXPECTED_MESSAGE 244 # define SSL_R_UNEXPECTED_RECORD 245 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index d114fb5..8fc1b49 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -30,9 +30,9 @@ extern "C" { # define TLS1_3_VERSION 0x0304 # define TLS_MAX_VERSION TLS1_3_VERSION -/* TODO(TLS1.3) REMOVE ME: Version indicator for draft -21 */ -# define TLS1_3_VERSION_DRAFT 0x7f15 -# define TLS1_3_VERSION_DRAFT_TXT "TLS 1.3 (draft 21)" +/* TODO(TLS1.3) REMOVE ME: Version indicator for draft -22 */ +# define TLS1_3_VERSION_DRAFT 0x7f16 +# define TLS1_3_VERSION_DRAFT_TXT "TLS 1.3 (draft 22)" /* Special value for method supporting multiple versions */ # define TLS_ANY_VERSION 0x10000 diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 5f01b04..5b0d2d6 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -816,7 +816,8 @@ 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_TREAT_AS_TLS13(s) ? TLS1_VERSION : s->version; + unsigned int version = SSL_TREAT_AS_TLS13(s) ? TLS1_2_VERSION + : s->version; unsigned char *compressdata = NULL; size_t maxcomplen; unsigned int rectype; diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index 213f001..28ee2cc 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -276,7 +276,7 @@ int ssl3_get_record(SSL *s) * that explicitly */ if (!s->first_packet && !SSL_IS_TLS13(s) - && !s->hello_retry_request + && s->hello_retry_request != SSL_HRR_PENDING && version != (unsigned int)s->version) { if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash) { @@ -333,8 +333,11 @@ int ssl3_get_record(SSL *s) } } - if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL - && thisrr->type != SSL3_RT_APPLICATION_DATA) { + if (SSL_IS_TLS13(s) + && s->enc_read_ctx != NULL + && thisrr->type != SSL3_RT_APPLICATION_DATA + && (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC + || !SSL_IS_FIRST_HANDSHAKE(s))) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD, SSL_R_BAD_RECORD_TYPE); return -1; @@ -444,6 +447,36 @@ int ssl3_get_record(SSL *s) & EVP_CIPH_FLAG_PIPELINE) && ssl3_record_app_data_waiting(s)); + if (num_recs == 1 + && thisrr->type == SSL3_RT_CHANGE_CIPHER_SPEC + && (SSL_IS_TLS13(s) || s->hello_retry_request != SSL_HRR_NONE) + && SSL_IS_FIRST_HANDSHAKE(s)) { + /* + * CCS messages must be exactly 1 byte long, containing the value 0x01 + */ + if (thisrr->length != 1 || thisrr->data[0] != 0x01) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_GET_RECORD, + SSL_R_INVALID_CCS_MESSAGE); + return -1; + } + /* + * CCS messages are ignored in TLSv1.3. We treat it like an empty + * handshake record + */ + thisrr->type = SSL3_RT_HANDSHAKE; + RECORD_LAYER_inc_empty_record_count(&s->rlayer); + if (RECORD_LAYER_get_empty_record_count(&s->rlayer) + > MAX_EMPTY_RECORDS) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD, + SSL_R_UNEXPECTED_CCS_MESSAGE); + return -1; + } + thisrr->read = 1; + RECORD_LAYER_set_numrpipes(&s->rlayer, 1); + + return 1; + } + /* * If in encrypt-then-mac mode calculate mac from encrypted record. All * the details below are public so no timing details can leak. diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index fe090ae..0cd8ace 100644 --- a/ssl/ssl_conf.c +++ b/ssl/ssl_conf.c @@ -369,7 +369,8 @@ static int cmd_Options(SSL_CONF_CTX *cctx, const char *value) SSL_FLAG_TBL_INV("EncryptThenMac", SSL_OP_NO_ENCRYPT_THEN_MAC), SSL_FLAG_TBL("NoRenegotiation", SSL_OP_NO_RENEGOTIATION), SSL_FLAG_TBL("AllowNoDHEKEX", SSL_OP_ALLOW_NO_DHE_KEX), - SSL_FLAG_TBL("PrioritizeChaCha", SSL_OP_PRIORITIZE_CHACHA) + SSL_FLAG_TBL("PrioritizeChaCha", SSL_OP_PRIORITIZE_CHACHA), + SSL_FLAG_TBL("MiddleboxCompat", SSL_OP_ENABLE_MIDDLEBOX_COMPAT) }; if (value == NULL) return -3; @@ -591,6 +592,7 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = { SSL_CONF_CMD_SWITCH("allow_no_dhe_kex", 0), SSL_CONF_CMD_SWITCH("prioritize_chacha", SSL_CONF_FLAG_SERVER), SSL_CONF_CMD_SWITCH("strict", 0), + SSL_CONF_CMD_SWITCH("no_middlebox", 0), SSL_CONF_CMD_STRING(SignatureAlgorithms, "sigalgs", 0), SSL_CONF_CMD_STRING(ClientSignatureAlgorithms, "client_sigalgs", 0), SSL_CONF_CMD_STRING(Curves, "curves", 0), @@ -665,6 +667,8 @@ static const ssl_switch_tbl ssl_cmd_switches[] = { /* chacha reprioritization */ {SSL_OP_PRIORITIZE_CHACHA, 0}, {SSL_CERT_FLAG_TLS_STRICT, SSL_TFLAG_CERT}, /* strict */ + /* no_middlebox */ + {SSL_OP_ENABLE_MIDDLEBOX_COMPAT, SSL_TFLAG_INV}, }; static int ssl_conf_cmd_skip_prefix(SSL_CONF_CTX *cctx, const char **pcmd) diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 7b201e0..1e3eb2c 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -524,6 +524,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "tls_construct_stoc_status_request"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, 0), "tls_construct_stoc_supported_groups"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS, 0), + "tls_construct_stoc_supported_versions"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP, 0), "tls_construct_stoc_use_srtp"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, 0), @@ -593,6 +595,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "tls_parse_stoc_session_ticket"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_STATUS_REQUEST, 0), "tls_parse_stoc_status_request"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS, 0), + "tls_parse_stoc_supported_versions"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_USE_SRTP, 0), "tls_parse_stoc_use_srtp"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, 0), @@ -601,6 +605,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "tls_post_process_client_key_exchange"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE, 0), "tls_prepare_client_certificate"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST, 0), + "tls_process_as_hello_retry_request"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, 0), "tls_process_certificate_request"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CERT_STATUS, 0), ""}, @@ -700,6 +706,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_STATE), "bad handshake state"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HELLO_REQUEST), "bad hello request"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HRR_VERSION), "bad hrr version"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_KEY_SHARE), "bad key share"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_KEY_UPDATE), "bad key update"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_LENGTH), "bad length"}, @@ -848,6 +855,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INSUFFICIENT_SECURITY), "insufficient security"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_ALERT), "invalid alert"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CCS_MESSAGE), + "invalid ccs message"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CERTIFICATE_OR_ALG), "invalid certificate or alg"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "invalid command"}, @@ -867,6 +876,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "invalid sequence number"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA), "invalid serverinfo data"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SESSION_ID), "invalid session id"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME), "invalid srp username"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE), @@ -1120,6 +1130,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "unable to load ssl3 md5 routines"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES), "unable to load ssl3 sha1 routines"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_CCS_MESSAGE), + "unexpected ccs message"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_END_OF_EARLY_DATA), "unexpected end of early data"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "unexpected message"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 2007318..bba0291 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2894,9 +2894,11 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) * Disable compression by default to prevent CRIME. Applications can * re-enable compression by configuring * SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION); - * or by using the SSL_CONF library. + * or by using the SSL_CONF library. Similarly we also enable TLSv1.3 + * middlebox compatibility by default. This may be disabled by default in + * a later OpenSSL version. */ - ret->options |= SSL_OP_NO_COMPRESSION; + ret->options |= SSL_OP_NO_COMPRESSION | SSL_OP_ENABLE_MIDDLEBOX_COMPAT; ret->ext.status_type = TLSEXT_STATUSTYPE_nothing; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 952a8f9..eec5be3 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -323,10 +323,14 @@ && (s)->method->version != TLS_ANY_VERSION) # define SSL_TREAT_AS_TLS13(s) \ - (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_WRITING \ - || (s)->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) + (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_CONNECTING \ + || (s)->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY \ + || (s)->early_data_state == SSL_EARLY_DATA_WRITING \ + || (s)->early_data_state == SSL_EARLY_DATA_WRITE_RETRY \ + || (s)->hello_retry_request == SSL_HRR_PENDING) -# define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0) +# define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0 \ + || (s)->s3->tmp.peer_finish_md_len == 0) /* See if we need explicit IV */ # define SSL_USE_EXPLICIT_IV(s) \ @@ -1116,7 +1120,8 @@ struct ssl_st { size_t cert_verify_hash_len; /* Flag to indicate whether we should send a HelloRetryRequest or not */ - int hello_retry_request; + enum {SSL_HRR_NONE = 0, SSL_HRR_PENDING, SSL_HRR_COMPLETE} + hello_retry_request; /* * the session_id_context is used to ensure sessions are only reused in @@ -1132,6 +1137,12 @@ struct ssl_st { size_t psksession_id_len; /* Default generate session ID callback. */ GEN_SESSION_CB generate_session_id; + /* + * The temporary TLSv1.3 session id. This isn't really a session id at all + * but is a random value sent in the legacy session id field. + */ + unsigned char tmp_session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + size_t tmp_session_id_len; /* Used in SSL3 */ /* * 0 don't care about verify failure. @@ -2266,7 +2277,8 @@ __owur int ssl_check_version_downgrade(SSL *s); __owur int ssl_set_version_bound(int method_version, int version, int *bound); __owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd); -__owur int ssl_choose_client_version(SSL *s, int version, int checkdgrd); +__owur int ssl_choose_client_version(SSL *s, int version, + RAW_EXTENSION *extensions); int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version); __owur long tls1_default_timeout(void); diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c index 5dd71d2..179513b 100644 --- a/ssl/ssl_stat.c +++ b/ssl/ssl_stat.c @@ -97,10 +97,6 @@ const char *SSL_state_string_long(const SSL *s) return "TLSv1.3 write server certificate verify"; case TLS_ST_CR_HELLO_REQ: return "SSLv3/TLS read hello request"; - case TLS_ST_SW_HELLO_RETRY_REQUEST: - return "TLSv1.3 write hello retry request"; - case TLS_ST_CR_HELLO_RETRY_REQUEST: - return "TLSv1.3 read hello retry request"; case TLS_ST_SW_KEY_UPDATE: return "TLSv1.3 write server key update"; case TLS_ST_CW_KEY_UPDATE: @@ -208,10 +204,6 @@ const char *SSL_state_string(const SSL *s) return "TRSCV"; case TLS_ST_CR_HELLO_REQ: return "TRHR"; - case TLS_ST_SW_HELLO_RETRY_REQUEST: - return "TWHRR"; - case TLS_ST_CR_HELLO_RETRY_REQUEST: - return "TRHRR"; case TLS_ST_SW_KEY_UPDATE: return "TWSKU"; case TLS_ST_CW_KEY_UPDATE: diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 464a5ef..28f7ada 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -9,6 +9,7 @@ #include <string.h> #include "internal/nelem.h" +#include "internal/cryptlib.h" #include "../ssl_locl.h" #include "statem_locl.h" @@ -261,11 +262,14 @@ static const EXTENSION_DEFINITION ext_defs[] = { }, { TLSEXT_TYPE_supported_versions, - SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS_IMPLEMENTATION_ONLY - | SSL_EXT_TLS1_3_ONLY, + SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO + | SSL_EXT_TLS1_3_SERVER_HELLO | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST + | SSL_EXT_TLS_IMPLEMENTATION_ONLY, NULL, /* Processed inline as part of version selection */ - NULL, NULL, NULL, tls_construct_ctos_supported_versions, NULL + NULL, tls_parse_stoc_supported_versions, + tls_construct_stoc_supported_versions, + tls_construct_ctos_supported_versions, NULL }, { TLSEXT_TYPE_psk_kex_modes, @@ -357,6 +361,44 @@ static int validate_context(SSL *s, unsigned int extctx, unsigned int thisctx) return 1; } +int tls_validate_all_contexts(SSL *s, unsigned int thisctx, RAW_EXTENSION *exts) +{ + size_t i, num_exts, builtin_num = OSSL_NELEM(ext_defs), offset; + RAW_EXTENSION *thisext; + unsigned int context; + ENDPOINT role = ENDPOINT_BOTH; + + if ((thisctx & SSL_EXT_CLIENT_HELLO) != 0) + role = ENDPOINT_SERVER; + else if ((thisctx & SSL_EXT_TLS1_2_SERVER_HELLO) != 0) + role = ENDPOINT_CLIENT; + + /* Calculate the number of extensions in the extensions list */ + num_exts = builtin_num + s->cert->custext.meths_count; + + for (thisext = exts, i = 0; i < num_exts; i++, thisext++) { + if (!thisext->present) + continue; + + if (i < builtin_num) { + context = ext_defs[i].context; + } else { + custom_ext_method *meth = NULL; + + meth = custom_ext_find(&s->cert->custext, role, thisext->type, + &offset); + if (!ossl_assert(meth != NULL)) + return 0; + context = meth->context; + } + + if (!validate_context(s, context, thisctx)) + return 0; + } + + return 1; +} + /* * Verify whether we are allowed to use the extension |type| in the current * |context|. Returns 1 to indicate the extension is allowed or unknown or 0 to @@ -1194,7 +1236,7 @@ static int final_key_share(SSL *s, unsigned int context, int sent) */ if (s->server && s->s3->peer_tmp == NULL) { /* No suitable share */ - if (s->hello_retry_request == 0 && sent + if (s->hello_retry_request == SSL_HRR_NONE && sent && (!s->hit || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) != 0)) { @@ -1219,7 +1261,7 @@ static int final_key_share(SSL *s, unsigned int context, int sent) if (i < num_groups) { /* A shared group exists so send a HelloRetryRequest */ s->s3->group_id = group_id; - s->hello_retry_request = 1; + s->hello_retry_request = SSL_HRR_PENDING; return 1; } } @@ -1234,8 +1276,8 @@ static int final_key_share(SSL *s, unsigned int context, int sent) } /* We have a key_share so don't send any more HelloRetryRequest messages */ - if (s->server) - s->hello_retry_request = 0; + if (s->server && s->hello_retry_request == SSL_HRR_PENDING) + s->hello_retry_request = SSL_HRR_COMPLETE; /* * For a client side resumption with no key_share we need to generate @@ -1364,7 +1406,7 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart, * following a HelloRetryRequest then this includes the hash of the first * ClientHello and the HelloRetryRequest itself. */ - if (s->hello_retry_request) { + if (s->hello_retry_request == SSL_HRR_PENDING) { size_t hdatalen; void *hdata; @@ -1475,7 +1517,7 @@ static int final_early_data(SSL *s, unsigned int context, int sent) || s->session->ext.tick_identity != 0 || s->early_data_state != SSL_EARLY_DATA_ACCEPTING || !s->ext.early_data_ok - || s->hello_retry_request) { + || s->hello_retry_request != SSL_HRR_NONE) { s->ext.early_data = SSL_EARLY_DATA_REJECTED; } else { s->ext.early_data = SSL_EARLY_DATA_ACCEPTED; diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index b7ef54e..2b39459 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -507,6 +507,20 @@ EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, { int currv, min_version, max_version, reason; + reason = ssl_get_min_max_version(s, &min_version, &max_version); + if (reason != 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, reason); + return EXT_RETURN_FAIL; + } + + /* + * Don't include this if we can't negotiate TLSv1.3. We can do a straight + * comparison here because we will never be called in DTLS. + */ + if (max_version < TLS1_3_VERSION) + return EXT_RETURN_NOT_SENT; + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions) || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_start_sub_packet_u8(pkt)) { @@ -516,13 +530,6 @@ EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, return EXT_RETURN_FAIL; } - reason = ssl_get_min_max_version(s, &min_version, &max_version); - if (reason != 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, reason); - return EXT_RETURN_FAIL; - } - /* * TODO(TLS1.3): There is some discussion on the TLS list as to whether * we should include versions <TLS1.2. For the moment we do. To be @@ -592,7 +599,7 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id) size_t encodedlen; if (s->s3->tmp.pkey != NULL) { - if (!ossl_assert(s->hello_retry_request)) { + if (!ossl_assert(s->hello_retry_request == SSL_HRR_PENDING)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_ADD_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; @@ -742,7 +749,7 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, SSL_SESSION *edsess = NULL; const EVP_MD *handmd = NULL; - if (s->hello_retry_request) + if (s->hello_retry_request == SSL_HRR_PENDING) handmd = ssl_handshake_md(s); if (s->psk_use_session_cb != NULL @@ -954,7 +961,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, || (s->session->ext.ticklen == 0 && s->psksession == NULL)) return EXT_RETURN_NOT_SENT; - if (s->hello_retry_request) + if (s->hello_retry_request == SSL_HRR_PENDING) handmd = ssl_handshake_md(s); if (s->session->ext.ticklen != 0) { @@ -973,7 +980,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, goto dopsksess; } - if (s->hello_retry_request && mdres != handmd) { + if (s->hello_retry_request == SSL_HRR_PENDING && mdres != handmd) { /* * Selected ciphersuite hash does not match the hash for the session * so we can't use it. @@ -1037,7 +1044,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_FAIL; } - if (s->hello_retry_request && mdpsk != handmd) { + if (s->hello_retry_request == SSL_HRR_PENDING && mdpsk != handmd) { /* * Selected ciphersuite hash does not match the hash for the PSK * session. This is an application bug. @@ -1633,6 +1640,44 @@ int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 1; } +int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + unsigned int version; + + if (!PACKET_get_net_2(pkt, &version) + || PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, + SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + /* TODO(TLS1.3): Remove this before release */ + if (version == TLS1_3_VERSION_DRAFT) + version = TLS1_3_VERSION; + + /* We ignore this extension for HRRs except to sanity check it */ + if (context == SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) { + /* + * The only protocol version we support which has an HRR message is + * TLSv1.3, therefore we shouldn't be getting an HRR for anything else. + */ + if (version != TLS1_3_VERSION) { + SSLfatal(s, SSL_AD_PROTOCOL_VERSION, + SSL_F_TLS_PARSE_STOC_SUPPORTED_VERSIONS, + SSL_R_BAD_HRR_VERSION); + return 0; + } + return 1; + } + + /* We just set it here. We validate it in ssl_choose_client_version */ + s->version = version; + + return 1; +} + int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index b07376f..d34a7c5 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -704,7 +704,7 @@ int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context, return 0; } - if (s->hello_retry_request) { + if (s->hello_retry_request != SSL_HRR_NONE) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_EARLY_DATA, SSL_R_BAD_EXTENSION); return 0; @@ -1213,6 +1213,27 @@ EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_SENT; } +EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + if (!SSL_IS_TLS13(s)) + return EXT_RETURN_NOT_SENT; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions) + || !WPACKET_start_sub_packet_u16(pkt) + /* TODO(TLS1.3): Update to remove the TLSv1.3 draft indicator */ + || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS, + ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} + EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) @@ -1224,7 +1245,7 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, if (ckey == NULL) { /* No key_share received from client */ - if (s->hello_retry_request) { + if (s->hello_retry_request == SSL_HRR_PENDING) { if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share) || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_put_bytes_u16(pkt, s->s3->group_id) diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index a7a5a17..51cdd58 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -22,7 +22,7 @@ #include <openssl/bn.h> #include <openssl/engine.h> -static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt); +static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s, PACKET *pkt); static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt); static ossl_inline int cert_req_allowed(SSL *s); @@ -206,11 +206,6 @@ int ossl_statem_client_read_transition(SSL *s, int mt) st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST; return 1; } - } else { - if (mt == SSL3_MT_HELLO_RETRY_REQUEST) { - st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST; - return 1; - } } break; @@ -224,10 +219,6 @@ int ossl_statem_client_read_transition(SSL *s, int mt) 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: @@ -391,14 +382,13 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s) ERR_R_INTERNAL_ERROR); return WRITE_TRAN_ERROR; - case TLS_ST_CW_CLNT_HELLO: - /* We only hit this in the case of HelloRetryRequest */ - return WRITE_TRAN_FINISHED; - case TLS_ST_CR_FINISHED: if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY || s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING) st->hand_state = TLS_ST_PENDING_EARLY_DATA_END; + else if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0 + && s->hello_retry_request == SSL_HRR_NONE) + st->hand_state = TLS_ST_CW_CHANGE; else st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT : TLS_ST_CW_FINISHED; @@ -412,6 +402,7 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s) /* Fall through */ case TLS_ST_CW_END_OF_EARLY_DATA: + case TLS_ST_CW_CHANGE: st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT : TLS_ST_CW_FINISHED; return WRITE_TRAN_CONTINUE; @@ -494,7 +485,10 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s) * 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; + if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0) + st->hand_state = TLS_ST_CW_CHANGE; + else + st->hand_state = TLS_ST_EARLY_DATA; return WRITE_TRAN_CONTINUE; } /* @@ -503,8 +497,17 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s) */ return WRITE_TRAN_FINISHED; - case TLS_ST_CR_HELLO_RETRY_REQUEST: - st->hand_state = TLS_ST_CW_CLNT_HELLO; + case TLS_ST_CR_SRVR_HELLO: + /* + * We only get here in TLSv1.3. We just received an HRR, so issue a + * CCS unless middlebox compat mode is off, or we already issued one + * because we did early data. + */ + if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0 + && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING) + st->hand_state = TLS_ST_CW_CHANGE; + else + st->hand_state = TLS_ST_CW_CLNT_HELLO; return WRITE_TRAN_CONTINUE; case TLS_ST_EARLY_DATA: @@ -551,15 +554,20 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s) return WRITE_TRAN_CONTINUE; case TLS_ST_CW_CHANGE: + if (s->hello_retry_request == SSL_HRR_PENDING) { + st->hand_state = TLS_ST_CW_CLNT_HELLO; + } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) { + st->hand_state = TLS_ST_EARLY_DATA; + } else { #if defined(OPENSSL_NO_NEXTPROTONEG) - 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; - else 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; + else + st->hand_state = TLS_ST_CW_FINISHED; #endif + } return WRITE_TRAN_CONTINUE; #if !defined(OPENSSL_NO_NEXTPROTONEG) @@ -681,14 +689,6 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst) break; case TLS_ST_CW_CLNT_HELLO: - if (wst == WORK_MORE_A && statem_flush(s) != 1) - return WORK_MORE_A; - - if (SSL_IS_DTLS(s)) { - /* 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) { /* @@ -696,11 +696,23 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst) * 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)) { - /* SSLfatal() already called */ - return WORK_ERROR; + if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) == 0) { + if (!statem_flush(s)) + return WORK_MORE_A; + if (!tls13_change_cipher_state(s, + SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { + /* SSLfatal() already called */ + return WORK_ERROR; + } } + /* else we're in compat mode so we delay flushing until after CCS */ + } else if (!statem_flush(s)) { + return WORK_MORE_A; + } + + if (SSL_IS_DTLS(s)) { + /* Treat the next message as the first packet */ + s->first_packet = 1; } break; @@ -721,6 +733,22 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst) break; case TLS_ST_CW_CHANGE: + if (SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING) + break; + if (s->early_data_state == SSL_EARLY_DATA_CONNECTING + && s->max_early_data > 0) { + if (statem_flush(s) != 1) + return WORK_MORE_A; + /* + * 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; + } s->session->cipher = s->s3->tmp.new_cipher; #ifdef OPENSSL_NO_COMP s->session->compress_meth = 0; @@ -891,9 +919,6 @@ size_t ossl_statem_client_max_message_size(SSL *s) case DTLS_ST_CR_HELLO_VERIFY_REQUEST: return HELLO_VERIFY_REQUEST_MAX_LENGTH; - case TLS_ST_CR_HELLO_RETRY_REQUEST: - return HELLO_RETRY_REQUEST_MAX_LENGTH; - case TLS_ST_CR_CERT: return s->max_cert_list; @@ -957,9 +982,6 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt) case DTLS_ST_CR_HELLO_VERIFY_REQUEST: return dtls_process_hello_verify(s, pkt); - case TLS_ST_CR_HELLO_RETRY_REQUEST: - return tls_process_hello_retry_request(s, pkt); - case TLS_ST_CR_CERT: return tls_process_server_certificate(s, pkt); @@ -1028,6 +1050,7 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt) SSL_COMP *comp; #endif SSL_SESSION *sess = s->session; + unsigned char *session_id; if (!WPACKET_set_max_size(pkt, SSL3_RT_MAX_PLAIN_LENGTH)) { /* Should not happen */ @@ -1047,7 +1070,8 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt) if (sess == NULL || !ssl_version_supported(s, sess->ssl_version) || !SSL_SESSION_is_resumable(sess)) { - if (!ssl_get_new_session(s, 0)) { + if (s->hello_retry_request == SSL_HRR_NONE + && !ssl_get_new_session(s, 0)) { /* SSLfatal() already called */ return 0; } @@ -1070,7 +1094,7 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt) } } } else { - i = s->hello_retry_request == 0; + i = (s->hello_retry_request == SSL_HRR_NONE); } if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random), @@ -1121,13 +1145,34 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt) } /* Session ID */ - if (s->new_session || s->session->ssl_version == TLS1_3_VERSION) - sess_id_len = 0; - else + session_id = s->session->session_id; + if (s->new_session || s->session->ssl_version == TLS1_3_VERSION) { + if (s->version == TLS1_3_VERSION + && (s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0) { + sess_id_len = sizeof(s->tmp_session_id); + s->tmp_session_id_len = sess_id_len; + session_id = s->tmp_session_id; + if (s->hello_retry_request == SSL_HRR_NONE + && ssl_randbytes(s, s->tmp_session_id, + sess_id_len) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, + ERR_R_INTERNAL_ERROR); + return 0; + } + } else { + sess_id_len = 0; + } + } else { sess_id_len = s->session->session_id_length; + if (s->version == TLS1_3_VERSION) { + s->tmp_session_id_len = sess_id_len; + memcpy(s->tmp_session_id, s->session->session_id, sess_id_len); + } + } if (sess_id_len > sizeof(s->session->session_id) || !WPACKET_start_sub_packet_u8(pkt) - || (sess_id_len != 0 && !WPACKET_memcpy(pkt, s->session->session_id, + || (sess_id_len != 0 && !WPACKET_memcpy(pkt, session_id, sess_id_len)) || !WPACKET_close(pkt)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, @@ -1310,6 +1355,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) PACKET session_id, extpkt; size_t session_id_len; const unsigned char *cipherchars; + int hrr = 0; unsigned int compression; unsigned int sversion; unsigned int context; @@ -1326,50 +1372,37 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) } /* load the server random */ - if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO, - SSL_R_LENGTH_MISMATCH); - goto err; - } - - /* - * We do this immediately so we know what format the ServerHello is in. - * Must be done after reading the random data so we can check for the - * TLSv1.3 downgrade sentinels - */ - if (!ssl_choose_client_version(s, sversion, 1)) { - /* SSLfatal() already called */ - goto err; - } - - /* - * In TLSv1.3 a ServerHello message signals a key change so the end of the - * message must be on a record boundary. - */ - if (SSL_IS_TLS13(s) && RECORD_LAYER_processed_read_pending(&s->rlayer)) { - SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_SERVER_HELLO, - SSL_R_NOT_ON_RECORD_BOUNDARY); - goto err; - } - - /* Get the session-id. */ - if (!SSL_IS_TLS13(s)) { - if (!PACKET_get_length_prefixed_1(pkt, &session_id)) { + if (s->version == TLS1_3_VERSION + && sversion == TLS1_2_VERSION + && PACKET_remaining(pkt) >= SSL3_RANDOM_SIZE + && memcmp(hrrrandom, PACKET_data(pkt), SSL3_RANDOM_SIZE) == 0) { + s->hello_retry_request = SSL_HRR_PENDING; + hrr = 1; + if (!PACKET_forward(pkt, SSL3_RANDOM_SIZE)) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); goto err; } - session_id_len = PACKET_remaining(&session_id); - if (session_id_len > sizeof(s->session->session_id) - || session_id_len > SSL3_SESSION_ID_SIZE) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_F_TLS_PROCESS_SERVER_HELLO, - SSL_R_SSL3_SESSION_ID_TOO_LONG); + } else { + if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_LENGTH_MISMATCH); goto err; } - } else { - PACKET_null_init(&session_id); - session_id_len = 0; + } + + /* Get the session-id. */ + if (!PACKET_get_length_prefixed_1(pkt, &session_id)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_LENGTH_MISMATCH); + goto err; + } + session_id_len = PACKET_remaining(&session_id); + if (session_id_len > sizeof(s->session->session_id) + || session_id_len > SSL3_SESSION_ID_SIZE) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_SSL3_SESSION_ID_TOO_LONG); + goto err; } if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) { @@ -1378,18 +1411,14 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) goto err; } - if (!SSL_IS_TLS13(s)) { - if (!PACKET_get_1(pkt, &compression)) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO, - SSL_R_LENGTH_MISMATCH); - goto err; - } - } else { - compression = 0; + if (!PACKET_get_1(pkt, &compression)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_LENGTH_MISMATCH); + goto err; } /* TLS extensions */ - if (PACKET_remaining(pkt) == 0) { + if (PACKET_remaining(pkt) == 0 && !hrr) { PACKET_null_init(&extpkt); } else if (!PACKET_as_length_prefixed_2(pkt, &extpkt) || PACKET_remaining(pkt) != 0) { @@ -1398,20 +1427,77 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) goto err; } + if (!hrr) { + if (!tls_collect_extensions(s, &extpkt, + SSL_EXT_TLS1_2_SERVER_HELLO + | SSL_EXT_TLS1_3_SERVER_HELLO, + &extensions, NULL, 1)) { + /* SSLfatal() already called */ + goto err; + } + + if (!ssl_choose_client_version(s, sversion, extensions)) { + /* SSLfatal() already called */ + goto err; + } + } + + if (SSL_IS_TLS13(s) || hrr) { + if (compression != 0) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, + SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_INVALID_COMPRESSION_ALGORITHM); + goto err; + } + + if (session_id_len != s->tmp_session_id_len + || memcmp(PACKET_data(&session_id), s->tmp_session_id, + session_id_len) != 0) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, + SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INVALID_SESSION_ID); + goto err; + } + } + + if (hrr) { + if (!set_client_ciphersuite(s, cipherchars)) { + /* SSLfatal() already called */ + goto err; + } + + return tls_process_as_hello_retry_request(s, &extpkt); + } + + /* + * Now we have chosen the version we need to check again that the extensions + * are appropriate for this version. + */ context = SSL_IS_TLS13(s) ? SSL_EXT_TLS1_3_SERVER_HELLO : SSL_EXT_TLS1_2_SERVER_HELLO; - if (!tls_collect_extensions(s, &extpkt, context, &extensions, NULL, 1)) { - /* SSLfatal() already called */ + if (!tls_validate_all_contexts(s, context, extensions)) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_BAD_EXTENSION); goto err; } s->hit = 0; if (SSL_IS_TLS13(s)) { + /* + * In TLSv1.3 a ServerHello message signals a key change so the end of + * the message must be on a record boundary. + */ + if (RECORD_LAYER_processed_read_pending(&s->rlayer)) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, + SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_NOT_ON_RECORD_BOUNDARY); + goto err; + } + /* This will set s->hit if we are resuming */ if (!tls_parse_extension(s, TLSEXT_IDX_psk, SSL_EXT_TLS1_3_SERVER_HELLO, - extensions, NULL, 0l)) { + extensions, NULL, 0)) { /* SSLfatal() already called */ goto err; } @@ -1489,11 +1575,19 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) } s->session->ssl_version = s->version; - s->session->session_id_length = session_id_len; - /* session_id_len could be 0 */ - if (session_id_len > 0) - memcpy(s->session->session_id, PACKET_data(&session_id), - session_id_len); + /* + * In TLSv1.2 and below we save the session id we were sent so we can + * resume it later. In TLSv1.3 the session id we were sent is just an + * echo of what we originally sent in the ClientHello and should not be + * used for resumption. + */ + if (!SSL_IS_TLS13(s)) { + s->session->session_id_length = session_id_len; + /* session_id_len could be 0 */ + if (session_id_len > 0) + memcpy(s->session->session_id, PACKET_data(&session_id), + session_id_len); + } } /* Session version and negotiated protocol version should match */ @@ -1605,28 +1699,10 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) return MSG_PROCESS_ERROR; } -static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt) +static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s, + PACKET *extpkt) { - unsigned int sversion; - const unsigned char *cipherchars; RAW_EXTENSION *extensions = NULL; - PACKET extpkt; - - if (!PACKET_get_net_2(pkt, &sversion)) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, - SSL_R_LENGTH_MISMATCH); - goto err; - } - - /* TODO(TLS1.3): Remove the TLS1_3_VERSION_DRAFT clause before release */ - if (sversion != TLS1_3_VERSION && sversion != TLS1_3_VERSION_DRAFT) { - SSLfatal(s, SSL_AD_PROTOCOL_VERSION, - SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, - SSL_R_WRONG_SSL_VERSION); - goto err; - } - - s->hello_retry_request = 1; /* * If we were sending early_data then the enc_write_ctx is now invalid and @@ -1635,28 +1711,7 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt) EVP_CIPHER_CTX_free(s->enc_write_ctx); s->enc_write_ctx = NULL; - if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, - SSL_R_LENGTH_MISMATCH); - goto err; - } - - if (!set_client_ciphersuite(s, cipherchars)) { - /* SSLfatal() already called */ - goto err; - } - - if (!PACKET_as_length_prefixed_2(pkt, &extpkt) - /* Must have a non-empty extensions block */ - || PACKET_remaining(&extpkt) == 0 - /* Must be no trailing data after extensions */ - || PACKET_remaining(pkt) != 0) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, - SSL_R_BAD_LENGTH); - goto err; - } - - if (!tls_collect_extensions(s, &extpkt, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST, + if (!tls_collect_extensions(s, extpkt, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST, &extensions, NULL, 1) || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST, extensions, NULL, 0, 1)) { @@ -1677,8 +1732,8 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt) * ClientHello will not change */ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, - SSL_R_NO_CHANGE_FOLLOWING_HRR); + SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST, + SSL_R_NO_CHANGE_FOLLOWING_HRR); goto err; } diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index b8e094b..b65dfa1 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -19,6 +19,13 @@ #include <openssl/evp.h> #include <openssl/x509.h> +/* Fixed value used in the ServerHello random field to identify an HRR */ +const unsigned char hrrrandom[] = { + 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, + 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, + 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c +}; + /* * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or * SSL3_RT_CHANGE_CIPHER_SPEC) @@ -1238,12 +1245,18 @@ int tls_get_message_body(SSL *s, size_t *len) * We defer feeding in the HRR until later. We'll do it as part of * processing the message */ - if (s->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST - && !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, - s->init_num + SSL3_HM_HEADER_LENGTH)) { - /* SSLfatal() already called */ - *len = 0; - return 0; +#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2) + if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO + || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE + || memcmp(hrrrandom, + s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET, + SSL3_RANDOM_SIZE) != 0) { + if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, + s->init_num + SSL3_HM_HEADER_LENGTH)) { + /* SSLfatal() already called */ + *len = 0; + return 0; + } } if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, @@ -1642,6 +1655,10 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) suppversions = &hello->pre_proc_exts[TLSEXT_IDX_supported_versions]; + /* If we did an HRR then supported versions is mandatory */ + if (!suppversions->present && s->hello_retry_request != SSL_HRR_NONE) + return SSL_R_UNSUPPORTED_PROTOCOL; + if (suppversions->present && !SSL_IS_DTLS(s)) { unsigned int candidate_vers = 0; unsigned int best_vers = 0; @@ -1686,10 +1703,10 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) } if (best_vers > 0) { - if (SSL_IS_TLS13(s)) { + if (s->hello_retry_request != SSL_HRR_NONE) { /* - * We get here if this is after a HelloRetryRequest. In this - * case we just check that we still negotiated TLSv1.3 + * This is after a HelloRetryRequest so we better check that we + * negotiated TLSv1.3 */ if (best_vers != TLS1_3_VERSION) return SSL_R_UNSUPPORTED_PROTOCOL; @@ -1739,21 +1756,32 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) * * @s: client SSL handle. * @version: The proposed version from the server's HELLO. - * @checkdgrd: Whether to check the downgrade sentinels in the server_random + * @extensions: The extensions received * * Returns 1 on success or 0 on error. */ -int ssl_choose_client_version(SSL *s, int version, int checkdgrd) +int ssl_choose_client_version(SSL *s, int version, RAW_EXTENSION *extensions) { const version_info *vent; const version_info *table; int highver = 0; + int origv; - /* TODO(TLS1.3): Remove this before release */ - if (version == TLS1_3_VERSION_DRAFT) - version = TLS1_3_VERSION; + origv = s->version; + s->version = version; - if (s->hello_retry_request && version != TLS1_3_VERSION) { + /* This will overwrite s->version if the extension is present */ + if (!tls_parse_extension(s, TLSEXT_IDX_supported_versions, + SSL_EXT_TLS1_2_SERVER_HELLO + | SSL_EXT_TLS1_3_SERVER_HELLO, extensions, + NULL, 0)) { + s->version = origv; + return 0; + } + + if (s->hello_retry_request != SSL_HRR_NONE + && s->version != TLS1_3_VERSION) { + s->version = origv; SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION, SSL_R_WRONG_SSL_VERSION); return 0; @@ -1761,7 +1789,8 @@ int ssl_choose_client_version(SSL *s, int version, int checkdgrd) switch (s->method->version) { default: - if (version != s->version) { + if (s->version != s->method->version) { + s->version = origv; SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION, SSL_R_WRONG_SSL_VERSION); @@ -1790,13 +1819,14 @@ int ssl_choose_client_version(SSL *s, int version, int checkdgrd) if (vent->cmeth == NULL) continue; - if (highver != 0 && version != vent->version) + if (highver != 0 && s->version != vent->version) continue; method = vent->cmeth(); err = ssl_method_error(s, method); if (err != 0) { - if (version == vent->version) { + if (s->version == vent->version) { + s->version = origv; SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION, err); return 0; @@ -1807,43 +1837,43 @@ int ssl_choose_client_version(SSL *s, int version, int checkdgrd) if (highver == 0) highver = vent->version; - if (version != vent->version) + if (s->version != vent->version) continue; #ifndef OPENSSL_NO_TLS13DOWNGRADE /* Check for downgrades */ - if (checkdgrd) { - if (version == TLS1_2_VERSION && highver > version) { - if (memcmp(tls12downgrade, - s->s3->server_random + SSL3_RANDOM_SIZE - - sizeof(tls12downgrade), - sizeof(tls12downgrade)) == 0) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_F_SSL_CHOOSE_CLIENT_VERSION, - SSL_R_INAPPROPRIATE_FALLBACK); - return 0; - } - } else if (!SSL_IS_DTLS(s) - && version < TLS1_2_VERSION - && highver > version) { - if (memcmp(tls11downgrade, - s->s3->server_random + SSL3_RANDOM_SIZE - - sizeof(tls11downgrade), - sizeof(tls11downgrade)) == 0) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_F_SSL_CHOOSE_CLIENT_VERSION, - SSL_R_INAPPROPRIATE_FALLBACK); - return 0; - } + if (s->version == TLS1_2_VERSION && highver > s->version) { + if (memcmp(tls12downgrade, + s->s3->server_random + SSL3_RANDOM_SIZE + - sizeof(tls12downgrade), + sizeof(tls12downgrade)) == 0) { + s->version = origv; + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, + SSL_F_SSL_CHOOSE_CLIENT_VERSION, + SSL_R_INAPPROPRIATE_FALLBACK); + return 0; + } + } else if (!SSL_IS_DTLS(s) + && s->version < TLS1_2_VERSION + && highver > s->version) { + if (memcmp(tls11downgrade, + s->s3->server_random + SSL3_RANDOM_SIZE + - sizeof(tls11downgrade), + sizeof(tls11downgrade)) == 0) { + s->version = origv; + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, + SSL_F_SSL_CHOOSE_CLIENT_VERSION, + SSL_R_INAPPROPRIATE_FALLBACK); + return 0; } } #endif s->method = method; - s->version = version; return 1; } + s->version = origv; SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION, SSL_R_UNSUPPORTED_PROTOCOL); return 0; diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index 888c0b5..5e0ce7e 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -35,6 +35,8 @@ /* Dummy message type */ #define SSL3_MT_DUMMY -1 +extern const unsigned char hrrrandom[]; + /* Message processing return codes */ typedef enum { /* Something bad happened */ @@ -161,6 +163,8 @@ typedef enum ext_return_en { EXT_RETURN_NOT_SENT } EXT_RETURN; +__owur int tls_validate_all_contexts(SSL *s, unsigned int thisctx, + RAW_EXTENSION *exts); __owur int extension_is_relevant(SSL *s, unsigned int extctx, unsigned int thisctx); __owur int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context, @@ -271,6 +275,9 @@ EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); @@ -388,6 +395,8 @@ int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index f95c19b..249ee40 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -24,7 +24,6 @@ #include <openssl/md5.h> static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt); -static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt); /* * ossl_statem_server13_read_transition() encapsulates the logic for the allowed @@ -49,7 +48,7 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt) break; case TLS_ST_EARLY_DATA: - if (s->hello_retry_request) { + if (s->hello_retry_request == SSL_HRR_PENDING) { if (mt == SSL3_MT_CLIENT_HELLO) { st->hand_state = TLS_ST_SR_CLNT_HELLO; return 1; @@ -392,18 +391,24 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) return WRITE_TRAN_FINISHED; case TLS_ST_SR_CLNT_HELLO: - if (s->hello_retry_request) - st->hand_state = TLS_ST_SW_HELLO_RETRY_REQUEST; - else - st->hand_state = TLS_ST_SW_SRVR_HELLO; + st->hand_state = TLS_ST_SW_SRVR_HELLO; return WRITE_TRAN_CONTINUE; - case TLS_ST_SW_HELLO_RETRY_REQUEST: - st->hand_state = TLS_ST_EARLY_DATA; + case TLS_ST_SW_SRVR_HELLO: + if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0 + && s->hello_retry_request != SSL_HRR_COMPLETE) + st->hand_state = TLS_ST_SW_CHANGE; + else if (s->hello_retry_request == SSL_HRR_PENDING) + st->hand_state = TLS_ST_EARLY_DATA; + else + st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS; return WRITE_TRAN_CONTINUE; - case TLS_ST_SW_SRVR_HELLO: - st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS; + case TLS_ST_SW_CHANGE: + if (s->hello_retry_request == SSL_HRR_PENDING) + st->hand_state = TLS_ST_EARLY_DATA; + else + st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS; return WRITE_TRAN_CONTINUE; case TLS_ST_SW_ENCRYPTED_EXTENSIONS: @@ -663,6 +668,8 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst) break; case TLS_ST_SW_CHANGE: + if (SSL_IS_TLS13(s)) + break; s->session->cipher = s->s3->tmp.new_cipher; if (!s->method->ssl3_enc->setup_key_block(s)) { /* SSLfatal() already called */ @@ -707,11 +714,6 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) /* No post work to be done */ break; - case TLS_ST_SW_HELLO_RETRY_REQUEST: - if (statem_flush(s) != 1) - return WORK_MORE_A; - break; - case TLS_ST_SW_HELLO_REQ: if (statem_flush(s) != 1) return WORK_MORE_A; @@ -737,6 +739,12 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) break; case TLS_ST_SW_SRVR_HELLO: + if (SSL_IS_TLS13(s) && s->hello_retry_request == SSL_HRR_PENDING) { + if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) == 0 + && statem_flush(s) != 1) + return WORK_MORE_A; + break; + } #ifndef OPENSSL_NO_SCTP if (SSL_IS_DTLS(s) && s->hit) { unsigned char sctpauthkey[64]; @@ -763,6 +771,18 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) sizeof(sctpauthkey), sctpauthkey); } #endif + if (!SSL_IS_TLS13(s) + || ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0 + && s->hello_retry_request != SSL_HRR_COMPLETE)) + break; + /* Fall through */ + + case TLS_ST_SW_CHANGE: + if (s->hello_retry_request == SSL_HRR_PENDING) { + if (!statem_flush(s)) + return WORK_MORE_A; + break; + } /* * TODO(TLS1.3): This actually causes a problem. We don't yet know * whether the next record we are going to receive is an unencrypted @@ -783,10 +803,9 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) /* SSLfatal() already called */ return WORK_ERROR; } + break; } - break; - case TLS_ST_SW_CHANGE: #ifndef OPENSSL_NO_SCTP if (SSL_IS_DTLS(s) && !s->hit) { /* @@ -951,11 +970,6 @@ int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt, *mt = SSL3_MT_ENCRYPTED_EXTENSIONS; break; - case TLS_ST_SW_HELLO_RETRY_REQUEST: - *confunc = tls_construct_hello_retry_request; - *mt = SSL3_MT_HELLO_RETRY_REQUEST; - break; - case TLS_ST_SW_KEY_UPDATE: *confunc = tls_construct_key_update; *mt = SSL3_MT_KEY_UPDATE; @@ -1266,7 +1280,8 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) if (clienthello->isv2) { unsigned int mt; - if (!SSL_IS_FIRST_HANDSHAKE(s) || s->hello_retry_request) { + if (!SSL_IS_FIRST_HANDSHAKE(s) + || s->hello_retry_request != SSL_HRR_NONE) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNEXPECTED_MESSAGE); goto err; @@ -1623,7 +1638,7 @@ static int tls_early_post_process_client_hello(SSL *s) SSL_R_NO_SHARED_CIPHER); goto err; } - if (s->hello_retry_request + if (s->hello_retry_request == SSL_HRR_PENDING && (s->s3->tmp.new_cipher == NULL || s->s3->tmp.new_cipher->id != cipher->id)) { /* @@ -1686,6 +1701,12 @@ static int tls_early_post_process_client_hello(SSL *s) } } + if (SSL_IS_TLS13(s)) { + memcpy(s->tmp_session_id, s->clienthello->session_id, + s->clienthello->session_id_len); + s->tmp_session_id_len = s->clienthello->session_id_len; + } + /* * If it is a hit, check that the cipher is in the list. In TLSv1.3 we check * ciphersuite compatibility with the session as part of resumption. @@ -2192,15 +2213,19 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) int compm; size_t sl, len; int version; + unsigned char *session_id; + int usetls13 = SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING; - /* TODO(TLS1.3): Remove the DRAFT conditional before release */ - version = SSL_IS_TLS13(s) ? TLS1_3_VERSION_DRAFT : s->version; + version = usetls13 ? TLS1_2_VERSION : s->version; if (!WPACKET_put_bytes_u16(pkt, version) /* * Random stuff. Filling of the server_random takes place in * tls_process_client_hello() */ - || !WPACKET_memcpy(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) { + || !WPACKET_memcpy(pkt, + s->hello_retry_request == SSL_HRR_PENDING + ? hrrrandom : s->s3->server_random, + SSL3_RANDOM_SIZE)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); return 0; @@ -2218,6 +2243,8 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) * session ID. * - However, if we want the new session to be single-use, * we send back a 0-length session ID. + * - In TLSv1.3 we echo back the session id sent to us by the client + * regardless * s->hit is non-zero in either case of session reuse, * so the following won't overwrite an ID that we're supposed * to send back. @@ -2227,7 +2254,14 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) && !s->hit)) s->session->session_id_length = 0; - sl = s->session->session_id_length; + if (usetls13) { + sl = s->tmp_session_id_len; + session_id = s->tmp_session_id; + } else { + sl = s->session->session_id_length; + session_id = s->session->session_id; + } + if (sl > sizeof(s->session->session_id)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); @@ -2238,28 +2272,43 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) #ifdef OPENSSL_NO_COMP compm = 0; #else - if (s->s3->tmp.new_compression == NULL) + if (usetls13 || s->s3->tmp.new_compression == NULL) compm = 0; else compm = s->s3->tmp.new_compression->id; #endif - if ((!SSL_IS_TLS13(s) - && !WPACKET_sub_memcpy_u8(pkt, s->session->session_id, sl)) + if (!WPACKET_sub_memcpy_u8(pkt, session_id, sl) || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len) - || (!SSL_IS_TLS13(s) - && !WPACKET_put_bytes_u8(pkt, compm)) + || !WPACKET_put_bytes_u8(pkt, compm) || !tls_construct_extensions(s, pkt, - SSL_IS_TLS13(s) - ? SSL_EXT_TLS1_3_SERVER_HELLO - : SSL_EXT_TLS1_2_SERVER_HELLO, + s->hello_retry_request + == SSL_HRR_PENDING + ? SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST + : (SSL_IS_TLS13(s) + ? SSL_EXT_TLS1_3_SERVER_HELLO + : SSL_EXT_TLS1_2_SERVER_HELLO), NULL, 0)) { /* SSLfatal() already called */ return 0; } - if (!(s->verify_mode & SSL_VERIFY_PEER) - && !ssl3_digest_cached_records(s, 0)) { + if (s->hello_retry_request == SSL_HRR_PENDING) { + /* Ditch the session. We'll create a new one next time around */ + SSL_SESSION_free(s->session); + s->session = NULL; + s->hit = 0; + + /* + * Re-initialise the Transcript Hash. We're going to prepopulate it with + * a synthetic message_hash in place of ClientHello1. + */ + if (!create_synthetic_message_hash(s)) { + /* SSLfatal() already called */ + return 0; + } + } else if (!(s->verify_mode & SSL_VERIFY_PEER) + && !ssl3_digest_cached_records(s, 0)) { /* SSLfatal() already called */; return 0; } @@ -3831,45 +3880,6 @@ static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt) return 1; } -static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt) -{ - size_t len = 0; - - /* - * TODO(TLS1.3): Remove the DRAFT version before release - * (should be s->version) - */ - if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT) - || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, - &len)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST, ERR_R_INTERNAL_ERROR); - return 0; - } - - if (!tls_construct_extensions(s, pkt, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST, - NULL, 0)) { - /* SSLfatal() already called */ - return 0; - } - - /* Ditch the session. We'll create a new one next time around */ - SSL_SESSION_free(s->session); - s->session = NULL; - s->hit = 0; - - /* - * Re-initialise the Transcript Hash. We're going to prepopulate it with - * a synthetic message_hash in place of ClientHello1. - */ - if (!create_synthetic_message_hash(s)) { - /* SSLfatal() already called */ - return 0; - } - - return 1; -} - MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt) { if (PACKET_remaining(pkt) != 0) { diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c index 13e3062..59d0efc 100644 --- a/ssl/t1_trce.c +++ b/ssl/t1_trce.c @@ -87,7 +87,6 @@ static const ssl_trace_tbl ssl_handshake_tbl[] = { {DTLS1_MT_HELLO_VERIFY_REQUEST, "HelloVerifyRequest"}, {SSL3_MT_NEWSESSION_TICKET, "NewSessionTicket"}, {SSL3_MT_END_OF_EARLY_DATA, "EndOfEarlyData"}, - {SSL3_MT_HELLO_RETRY_REQUEST, "HelloRetryRequest"}, {SSL3_MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions"}, {SSL3_MT_CERTIFICATE, "Certificate"}, {SSL3_MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange"}, @@ -783,11 +782,10 @@ static int ssl_print_extension(BIO *bio, int indent, int server, break; case TLSEXT_TYPE_key_share: - if (mt == SSL3_MT_HELLO_RETRY_REQUEST) { + if (server && extlen == 2) { int group_id; - if (extlen != 2) - return 0; + /* We assume this is an HRR, otherwise this is an invalid key_share */ group_id = (ext[0] << 8) | ext[1]; BIO_indent(bio, indent + 4, 80); BIO_printf(bio, "NamedGroup: %s (%d)\n", @@ -823,6 +821,17 @@ static int ssl_print_extension(BIO *bio, int indent, int server, break; case TLSEXT_TYPE_supported_versions: + if (server) { + int version; + + if (extlen != 2) + return 0; + version = (ext[0] << 8) | ext[1]; + BIO_indent(bio, indent + 4, 80); + BIO_printf(bio, "%s (%d)\n", + ssl_trace_str(version, ssl_version_tbl), version); + break; + } if (extlen < 1) return 0; xlen = ext[0]; @@ -1004,29 +1013,6 @@ static int ssl_print_server_hello(BIO *bio, int indent, return 1; } -static int ssl_print_hello_retry_request(BIO *bio, int indent, - const unsigned char *msg, - size_t msglen) -{ - unsigned int cs; - - if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, NULL)) - return 0; - - cs = (msg[0] << 8) | msg[1]; - BIO_indent(bio, indent, 80); - BIO_printf(bio, "cipher_suite {0x%02X, 0x%02X} %s\n", - msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl)); - msg += 2; - msglen -= 2; - - if (!ssl_print_extensions(bio, indent, 1, SSL3_MT_HELLO_RETRY_REQUEST, &msg, - &msglen)) - return 0; - - return 1; -} - static int ssl_get_keyex(const char **pname, const SSL *ssl) { unsigned long alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; @@ -1460,11 +1446,6 @@ static int ssl_print_handshake(BIO *bio, const SSL *ssl, int server, return 0; break; - case SSL3_MT_HELLO_RETRY_REQUEST: - if (!ssl_print_hello_retry_request(bio, indent + 2, msg, msglen)) - return 0; - break; - case SSL3_MT_ENCRYPTED_EXTENSIONS: if (!ssl_print_extensions(bio, indent + 2, 1, SSL3_MT_ENCRYPTED_EXTENSIONS, &msg, &msglen)) diff --git a/test/asynciotest.c b/test/asynciotest.c index fdb9770..179fe26 100644 --- a/test/asynciotest.c +++ b/test/asynciotest.c @@ -146,7 +146,7 @@ static int async_write(BIO *bio, const char *in, int inl) return -1; while (PACKET_remaining(&pkt) > 0) { - PACKET payload, wholebody; + PACKET payload, wholebody, sessionid, extensions; unsigned int contenttype, versionhi, versionlo, data; unsigned int msgtype = 0, negversion = 0; @@ -164,11 +164,43 @@ static int async_write(BIO *bio, const char *in, int inl) && !PACKET_get_1(&wholebody, &msgtype)) return -1; - if (msgtype == SSL3_MT_SERVER_HELLO - && (!PACKET_forward(&wholebody, + if (msgtype == SSL3_MT_SERVER_HELLO) { + if (!PACKET_forward(&wholebody, SSL3_HM_HEADER_LENGTH - 1) - || !PACKET_get_net_2(&wholebody, &negversion))) - return -1; + || !PACKET_get_net_2(&wholebody, &negversion) + /* Skip random (32 bytes) */ + || !PACKET_forward(&wholebody, 32) + /* Skip session id */ + || !PACKET_get_length_prefixed_1(&wholebody, + &sessionid) + /* + * Skip ciphersuite (2 bytes) and compression + * method (1 byte) + */ + || !PACKET_forward(&wholebody, 2 + 1) + || !PACKET_get_length_prefixed_2(&wholebody, + &extensions)) + return -1; + + /* + * Find the negotiated version in supported_versions + * extension, if present. + */ + while (PACKET_remaining(&extensions)) { + unsigned int type; + PACKET extbody; + + if (!PACKET_get_net_2(&extensions, &type) + || !PACKET_get_length_prefixed_2(&extensions, + &extbody)) + return -1; + + if (type == TLSEXT_TYPE_supported_versions + && (!PACKET_get_net_2(&extbody, &negversion) + || PACKET_remaining(&extbody) != 0)) + return -1; + } + } while (PACKET_get_1(&payload, &data)) { /* Create a new one byte long record for each byte in the diff --git a/test/build.info b/test/build.info index 3c92c80..c4c5441 100644 --- a/test/build.info +++ b/test/build.info @@ -46,7 +46,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN x509_time_test x509_dup_cert_test x509_check_cert_pkey_test \ recordlentest drbgtest sslbuffertest \ time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ - servername_test ocspapitest rsa_mp_test fatalerrtest + servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest SOURCE[aborttest]=aborttest.c INCLUDE[aborttest]=../include @@ -160,6 +160,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN INCLUDE[fatalerrtest]=../include .. DEPEND[fatalerrtest]=../libcrypto ../libssl libtestutil.a + SOURCE[tls13ccstest]=tls13ccstest.c ssltestlib.c + INCLUDE[tls13ccstest]=../include + DEPEND[tls13ccstest]=../libcrypto ../libssl libtestutil.a + SOURCE[evp_test]=evp_test.c INCLUDE[evp_test]=../include DEPEND[evp_test]=../libcrypto libtestutil.a diff --git a/test/clienthellotest.c b/test/clienthellotest.c index 8ba65ce..88e0a1c 100644 --- a/test/clienthellotest.c +++ b/test/clienthellotest.c @@ -90,6 +90,8 @@ static int test_client_hello(int currtest) case TEST_ADD_PADDING: case TEST_PADDING_NOT_NEEDED: SSL_CTX_set_options(ctx, SSL_OP_TLSEXT_PADDING); + /* Make sure we get a consistent size across TLS versions */ + SSL_CTX_clear_options(ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); /* * Add some dummy ALPN protocols so that the ClientHello is at least * F5_WORKAROUND_MIN_MSG_LEN bytes long - meaning padding will be diff --git a/test/recipes/70-test_key_share.t b/test/recipes/70-test_key_share.t index ae0a2b0..e2cdf09 100644 --- a/test/recipes/70-test_key_share.t +++ b/test/recipes/70-test_key_share.t @@ -223,6 +223,7 @@ ok(TLSProxy::Message->success(), "Ignore key_share for TLS<=1.2 server"); #Test 22: The server sending an HRR but not requesting a new key_share should # fail $proxy->clear(); +$direction = SERVER_TO_CLIENT; $testtype = NO_KEY_SHARES_IN_HRR; $proxy->serverflags("-curves X25519"); $proxy->start(); @@ -341,6 +342,12 @@ sub modify_key_shares_filter if ($testtype == LOOK_ONLY) { return; } + if ($testtype == NO_KEY_SHARES_IN_HRR) { + $message->delete_extension(TLSProxy::Message::EXT_KEY_SHARE); + $message->set_extension(TLSProxy::Message::EXT_UNKNOWN, ""); + $message->repack(); + return; + } if ($testtype == SELECT_X25519) { $ext = pack "C4H64", 0x00, 0x1d, #x25519 @@ -370,12 +377,7 @@ sub modify_key_shares_filter $message->set_extension(TLSProxy::Message::EXT_KEY_SHARE, $ext); $message->repack(); - } elsif ($message->mt == TLSProxy::Message::MT_HELLO_RETRY_REQUEST - && $testtype == NO_KEY_SHARES_IN_HRR) { - $message->delete_extension(TLSProxy::Message::EXT_KEY_SHARE); - $message->set_extension(TLSProxy::Message::EXT_UNKNOWN, ""); - $message->repack(); - } + } } } diff --git a/test/recipes/70-test_sslrecords.t b/test/recipes/70-test_sslrecords.t index ef46792..94dd11e 100644 --- a/test/recipes/70-test_sslrecords.t +++ b/test/recipes/70-test_sslrecords.t @@ -485,7 +485,8 @@ sub change_outer_record_type for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) { next; } - $i++; + #Skip CCS and ServerHello + $i += 2; ${$proxy->record_list}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE); } diff --git a/test/recipes/70-test_sslversions.t b/test/recipes/70-test_sslversions.t index 1f3db22..6044a05 100644 --- a/test/recipes/70-test_sslversions.t +++ b/test/recipes/70-test_sslversions.t @@ -87,7 +87,7 @@ $testtype = REVERSE_ORDER_VERSIONS; $proxy->start(); $record = pop @{$proxy->record_list}; ok(TLSProxy::Message->success() - && $record->version() == TLSProxy::Record::VERS_TLS_1_0 + && $record->version() == TLSProxy::Record::VERS_TLS_1_2 && TLSProxy::Proxy->is_tls13(), "Reverse order versions"); @@ -107,7 +107,7 @@ $testtype = WITH_TLS1_4; $proxy->start(); $record = pop @{$proxy->record_list}; ok(TLSProxy::Message->success() - && $record->version() == TLSProxy::Record::VERS_TLS_1_0 + && $record->version() == TLSProxy::Record::VERS_TLS_1_2 && TLSProxy::Proxy->is_tls13(), "TLS1.4 in supported versions extension"); diff --git a/test/recipes/70-test_tls13cookie.t b/test/recipes/70-test_tls13cookie.t index 3d3a10f..289e589 100644 --- a/test/recipes/70-test_tls13cookie.t +++ b/test/recipes/70-test_tls13cookie.t @@ -74,7 +74,7 @@ sub cookie_filter 0x04, 0x05; foreach my $message (@{$proxy->message_list}) { - if ($message->mt == TLSProxy::Message::MT_HELLO_RETRY_REQUEST + if ($message->mt == TLSProxy::Message::MT_SERVER_HELLO && ${$message->records}[0]->flight == 1) { $message->delete_extension(TLSProxy::Message::EXT_KEY_SHARE) if ($testtype == COOKIE_ONLY); diff --git a/test/recipes/70-test_tls13kexmodes.t b/test/recipes/70-test_tls13kexmodes.t index 97cbf76..7afb560 100644 --- a/test/recipes/70-test_tls13kexmodes.t +++ b/test/recipes/70-test_tls13kexmodes.t @@ -35,7 +35,7 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); @handmessages = ( [TLSProxy::Message::MT_CLIENT_HELLO, checkhandshake::ALL_HANDSHAKES], - [TLSProxy::Message::MT_HELLO_RETRY_REQUEST, + [TLSProxy::Message::MT_SERVER_HELLO, checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE], [TLSProxy::Message::MT_CLIENT_HELLO, checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE], @@ -90,7 +90,9 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK, checkhandshake::PSK_CLI_EXTENSION], - [TLSProxy::Message::MT_HELLO_RETRY_REQUEST, TLSProxy::Message::EXT_KEY_SHARE, + [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, + checkhandshake::DEFAULT_EXTENSIONS], + [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, checkhandshake::KEY_SHARE_HRR_EXTENSION], [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME, @@ -122,6 +124,8 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK, checkhandshake::PSK_CLI_EXTENSION], + [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, + checkhandshake::DEFAULT_EXTENSIONS], [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, checkhandshake::KEY_SHARE_SRV_EXTENSION], [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK, diff --git a/test/recipes/70-test_tls13messages.t b/test/recipes/70-test_tls13messages.t index 5bd2a96..2cf822a 100644 --- a/test/recipes/70-test_tls13messages.t +++ b/test/recipes/70-test_tls13messages.t @@ -35,7 +35,7 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); @handmessages = ( [TLSProxy::Message::MT_CLIENT_HELLO, checkhandshake::ALL_HANDSHAKES], - [TLSProxy::Message::MT_HELLO_RETRY_REQUEST, + [TLSProxy::Message::MT_SERVER_HELLO, checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE], [TLSProxy::Message::MT_CLIENT_HELLO, checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE], @@ -90,7 +90,9 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK, checkhandshake::PSK_CLI_EXTENSION], - [TLSProxy::Message::MT_HELLO_RETRY_REQUEST, TLSProxy::Message::EXT_KEY_SHARE, + [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, + checkhandshake::DEFAULT_EXTENSIONS], + [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, checkhandshake::KEY_SHARE_HRR_EXTENSION], [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME, @@ -122,6 +124,8 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf"); [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK, checkhandshake::PSK_CLI_EXTENSION], + [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, + checkhandshake::DEFAULT_EXTENSIONS], [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, checkhandshake::DEFAULT_EXTENSIONS], [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK, @@ -322,6 +326,6 @@ $proxy->start(); checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE, checkhandshake::DEFAULT_EXTENSIONS | checkhandshake::SUPPORTED_GROUPS_SRV_EXTENSION, - "Default handshake test"); + "Acceptable but non preferred key_share"); unlink $session; diff --git a/test/recipes/90-test_tls13encryption.t b/test/recipes/90-test_tls13ccs.t similarity index 60% copy from test/recipes/90-test_tls13encryption.t copy to test/recipes/90-test_tls13ccs.t index 63e62db..2ec28ce 100644 --- a/test/recipes/90-test_tls13encryption.t +++ b/test/recipes/90-test_tls13ccs.t @@ -1,15 +1,16 @@ #! /usr/bin/env perl -# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. +# 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 # https://www.openssl.org/source/license.html -use OpenSSL::Test; + use OpenSSL::Test::Utils; +use OpenSSL::Test qw/:DEFAULT srctop_file/; -my $test_name = "tls13encryption"; +my $test_name = "test_tls13ccs"; setup($test_name); plan skip_all => "$test_name is not supported in this build" @@ -17,4 +18,5 @@ plan skip_all => "$test_name is not supported in this build" plan tests => 1; -ok(run(test(["tls13encryptiontest"])), "running tls13encryptiontest"); +ok(run(test(["tls13ccstest", srctop_file("apps", "server.pem"), + srctop_file("apps", "server.pem")])), "tls13ccstest"); diff --git a/test/tls13ccstest.c b/test/tls13ccstest.c new file mode 100644 index 0000000..c51c2ce --- /dev/null +++ b/test/tls13ccstest.c @@ -0,0 +1,493 @@ +/* + * 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 + * https://www.openssl.org/source/license.html + */ + +#include <openssl/ssl.h> +#include <string.h> +#include "ssltestlib.h" +#include "testutil.h" +#include "../ssl/packet_locl.h" + +static char *cert = NULL; +static char *privkey = NULL; + +static BIO *s_to_c_fbio = NULL, *c_to_s_fbio = NULL; +static int chseen = 0, shseen = 0, sccsseen = 0, ccsaftersh = 0; +static int ccsbeforesh = 0, sappdataseen = 0, cappdataseen = 0, badccs = 0; +static int badvers = 0, badsessid = 0; + +static unsigned char chsessid[SSL_MAX_SSL_SESSION_ID_LENGTH]; +static size_t chsessidlen = 0; + +static int watchccs_new(BIO *bi); +static int watchccs_free(BIO *a); +static int watchccs_read(BIO *b, char *out, int outl); +static int watchccs_write(BIO *b, const char *in, int inl); +static long watchccs_ctrl(BIO *b, int cmd, long num, void *ptr); +static int watchccs_gets(BIO *bp, char *buf, int size); +static int watchccs_puts(BIO *bp, const char *str); + +/* Choose a sufficiently large type likely to be unused for this custom BIO */ +# define BIO_TYPE_WATCHCCS_FILTER (0x80 | BIO_TYPE_FILTER) + +static BIO_METHOD *method_watchccs = NULL; + +static const BIO_METHOD *bio_f_watchccs_filter() +{ + if (method_watchccs == NULL) { + method_watchccs = BIO_meth_new(BIO_TYPE_WATCHCCS_FILTER, + "Watch CCS filter"); + if ( method_watchccs == NULL + || !BIO_meth_set_write(method_watchccs, watchccs_write) + || !BIO_meth_set_read(method_watchccs, watchccs_read) + || !BIO_meth_set_puts(method_watchccs, watchccs_puts) + || !BIO_meth_set_gets(method_watchccs, watchccs_gets) + || !BIO_meth_set_ctrl(method_watchccs, watchccs_ctrl) + || !BIO_meth_set_create(method_watchccs, watchccs_new) + || !BIO_meth_set_destroy(method_watchccs, watchccs_free)) + return NULL; + } + return method_watchccs; +} + +static int watchccs_new(BIO *bio) +{ + BIO_set_init(bio, 1); + return 1; +} + +static int watchccs_free(BIO *bio) +{ + BIO_set_init(bio, 0); + return 1; +} + +static int watchccs_read(BIO *bio, char *out, int outl) +{ + int ret = 0; + BIO *next = BIO_next(bio); + + if (outl <= 0) + return 0; + if (next == NULL) + return 0; + + BIO_clear_retry_flags(bio); + + ret = BIO_read(next, out, outl); + if (ret <= 0 && BIO_should_read(next)) + BIO_set_retry_read(bio); + + return ret; +} + +static int watchccs_write(BIO *bio, const char *in, int inl) +{ + int ret = 0; + BIO *next = BIO_next(bio); + PACKET pkt, msg, msgbody, sessionid; + unsigned int rectype, recvers, msgtype, expectedrecvers; + + if (inl <= 0) + return 0; + if (next == NULL) + return 0; + + BIO_clear_retry_flags(bio); + + if (!PACKET_buf_init(&pkt, (const unsigned char *)in, inl)) + return 0; + + /* We assume that we always write complete records each time */ + while (PACKET_remaining(&pkt)) { + if (!PACKET_get_1(&pkt, &rectype) + || !PACKET_get_net_2(&pkt, &recvers) + || !PACKET_get_length_prefixed_2(&pkt, &msg)) + return 0; + + expectedrecvers = TLS1_2_VERSION; + + if (rectype == SSL3_RT_HANDSHAKE) { + if (!PACKET_get_1(&msg, &msgtype) + || !PACKET_get_length_prefixed_3(&msg, &msgbody)) + return 0; + if (msgtype == SSL3_MT_CLIENT_HELLO) { + chseen++; + expectedrecvers = TLS1_VERSION; + /* + * Skip legacy_version (2 bytes) and Random (32 bytes) to read + * session_id. + */ + if (!PACKET_forward(&msgbody, 34) + || !PACKET_get_length_prefixed_1(&msgbody, &sessionid)) + return 0; + + if (chseen == 1) { + /* Save the session id for later */ + chsessidlen = PACKET_remaining(&sessionid); + if (!PACKET_copy_bytes(&sessionid, chsessid, chsessidlen)) + return 0; + } else { + /* + * Check the session id for the second ClientHello is the + * same as the first one. + */ + if (PACKET_remaining(&sessionid) != chsessidlen + || (chsessidlen > 0 + && memcmp(chsessid, PACKET_data(&sessionid), + chsessidlen) != 0)) + badsessid = 1; + } + } else if (msgtype == SSL3_MT_SERVER_HELLO) { + shseen++; + /* + * Skip legacy_version (2 bytes) and Random (32 bytes) to read + * session_id. + */ + if (!PACKET_forward(&msgbody, 34) + || !PACKET_get_length_prefixed_1(&msgbody, &sessionid)) + return 0; + + /* + * Check the session id is the same as the one in the + * ClientHello + */ + if (PACKET_remaining(&sessionid) != chsessidlen + || (chsessidlen > 0 + && memcmp(chsessid, PACKET_data(&sessionid), + chsessidlen) != 0)) + badsessid = 1; + } + } else if (rectype == SSL3_RT_CHANGE_CIPHER_SPEC) { + if (bio == s_to_c_fbio) { + /* + * Server writing. We shouldn't have written any app data + * yet, and we should have seen both the ClientHello and the + * ServerHello + */ + if (!sappdataseen + && chseen == 1 + && shseen == 1 + && !sccsseen) + sccsseen = 1; + else + badccs = 1; + } else if (!cappdataseen) { + /* + * Client writing. We shouldn't have written any app data + * yet, and we should have seen the ClientHello + */ + if (shseen == 1 && !ccsaftersh) + ccsaftersh = 1; + else if (shseen == 0 && !ccsbeforesh) + ccsbeforesh = 1; + else + badccs = 1; + } else { + badccs = 1; + } + } else if(rectype == SSL3_RT_APPLICATION_DATA) { + if (bio == s_to_c_fbio) + sappdataseen = 1; + else + cappdataseen = 1; + } + if (recvers != expectedrecvers) + badvers = 1; + } + + ret = BIO_write(next, in, inl); + if (ret <= 0 && BIO_should_write(next)) + BIO_set_retry_write(bio); + + return ret; +} + +static long watchccs_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + long ret; + BIO *next = BIO_next(bio); + + if (next == NULL) + return 0; + + switch (cmd) { + case BIO_CTRL_DUP: + ret = 0; + break; + default: + ret = BIO_ctrl(next, cmd, num, ptr); + break; + } + return ret; +} + +static int watchccs_gets(BIO *bio, char *buf, int size) +{ + /* We don't support this - not needed anyway */ + return -1; +} + +static int watchccs_puts(BIO *bio, const char *str) +{ + return watchccs_write(bio, str, strlen(str)); +} + +static int test_tls13ccs(int tst) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *sssl = NULL, *cssl = NULL; + int ret = 0; + const char msg[] = "Dummy data"; + char buf[80]; + size_t written, readbytes; + SSL_SESSION *sess = NULL; + + chseen = shseen = sccsseen = ccsaftersh = ccsbeforesh = 0; + sappdataseen = cappdataseen = badccs = badvers = badsessid = 0; + chsessidlen = 0; + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), + &sctx, &cctx, cert, privkey))) + goto err; + + /* + * Test 0: Simple Handshake + * Test 1: Simple Handshake, client middlebox compat mode disabled + * Test 2: Simple Handshake, server middlebox compat mode disabled + * Test 3: HRR Handshake + * Test 4: HRR Handshake, client middlebox compat mode disabled + * Test 5: HRR Handshake, server middlebox compat mode disabled + * Test 6: Early data handshake + * Test 7: Early data handshake, client middlebox compat mode disabled + * Test 8: Early data handshake, server middlebox compat mode disabled + * Test 9: Early data then HRR + * Test 10: Early data then HRR, client middlebox compat mode disabled + * Test 11: Early data then HRR, server middlebox compat mode disabled + */ + switch (tst) { + case 0: + case 3: + case 6: + case 9: + break; + case 1: + case 4: + case 7: + case 10: + SSL_CTX_clear_options(cctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + break; + case 2: + case 5: + case 8: + case 11: + SSL_CTX_clear_options(sctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + break; + default: + TEST_error("Invalid test value"); + goto err; + } + + if (tst >= 6) { + /* Get a session suitable for early_data */ + if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL)) + || !TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE))) + goto err; + sess = SSL_get1_session(cssl); + if (!TEST_ptr(sess)) + goto err; + SSL_shutdown(cssl); + SSL_shutdown(sssl); + SSL_free(sssl); + SSL_free(cssl); + sssl = cssl = NULL; + } + + if ((tst >= 3 && tst <= 5) || tst >= 9) { + /* HRR handshake */ + if (!TEST_true(SSL_CTX_set1_groups_list(sctx, "P-256"))) + goto err; + } + + s_to_c_fbio = BIO_new(bio_f_watchccs_filter()); + c_to_s_fbio = BIO_new(bio_f_watchccs_filter()); + if (!TEST_ptr(s_to_c_fbio) + || !TEST_ptr(c_to_s_fbio)) { + BIO_free(s_to_c_fbio); + BIO_free(c_to_s_fbio); + goto err; + } + + /* BIOs get freed on error */ + if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, s_to_c_fbio, + c_to_s_fbio))) + goto err; + + if (tst >= 6) { + /* Early data */ + if (!TEST_true(SSL_set_session(cssl, sess)) + || !TEST_true(SSL_write_early_data(cssl, msg, strlen(msg), + &written)) + || (tst <= 8 + && !TEST_int_eq(SSL_read_early_data(sssl, buf, sizeof(buf), + &readbytes), + SSL_READ_EARLY_DATA_SUCCESS))) + goto err; + if (tst <= 8) { + if (!TEST_int_gt(SSL_connect(cssl), 0)) + goto err; + } else { + if (!TEST_int_le(SSL_connect(cssl), 0)) + goto err; + } + if (!TEST_int_eq(SSL_read_early_data(sssl, buf, sizeof(buf), + &readbytes), + SSL_READ_EARLY_DATA_FINISH)) + goto err; + } + + /* Perform handshake (or complete it if doing early data ) */ + if (!TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE))) + goto err; + + /* + * Check there were no unexpected CCS messages, all record versions + * were as expected, and that the session ids were reflected by the server + * correctly. + */ + if (!TEST_false(badccs) || !TEST_false(badvers) || !TEST_false(badsessid)) + goto err; + + switch (tst) { + case 0: + if (!TEST_true(sccsseen) + || !TEST_true(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 1: + if (!TEST_true(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_eq(chsessidlen, 0)) + goto err; + break; + + case 2: + if (!TEST_false(sccsseen) + || !TEST_true(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 3: + if (!TEST_true(sccsseen) + || !TEST_true(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 4: + if (!TEST_true(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_eq(chsessidlen, 0)) + goto err; + break; + + case 5: + if (!TEST_false(sccsseen) + || !TEST_true(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 6: + if (!TEST_true(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_true(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 7: + if (!TEST_true(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_eq(chsessidlen, 0)) + goto err; + break; + + case 8: + if (!TEST_false(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_true(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 9: + if (!TEST_true(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_true(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + case 10: + if (!TEST_true(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_false(ccsbeforesh) + || !TEST_size_t_eq(chsessidlen, 0)) + goto err; + break; + + case 11: + if (!TEST_false(sccsseen) + || !TEST_false(ccsaftersh) + || !TEST_true(ccsbeforesh) + || !TEST_size_t_gt(chsessidlen, 0)) + goto err; + break; + + default: + TEST_error("Invalid test value"); + goto err; + } + + ret = 1; + err: + SSL_SESSION_free(sess); + SSL_free(sssl); + SSL_free(cssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return ret; +} + +int setup_tests(void) +{ + if (!TEST_ptr(cert = test_get_argument(0)) + || !TEST_ptr(privkey = test_get_argument(1))) + return 0; + + ADD_ALL_TESTS(test_tls13ccs, 12); + + return 1; +} + +void cleanup_tests(void) +{ + BIO_meth_free(method_watchccs); +} diff --git a/util/perl/TLSProxy/HelloRetryRequest.pm b/util/perl/TLSProxy/HelloRetryRequest.pm deleted file mode 100644 index c4125b7..0000000 --- a/util/perl/TLSProxy/HelloRetryRequest.pm +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2016 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 -# https://www.openssl.org/source/license.html - -use strict; - -package TLSProxy::HelloRetryRequest; - -use vars '@ISA'; -push @ISA, 'TLSProxy::Message'; - -sub new -{ - my $class = shift; - my ($server, - $data, - $records, - $startoffset, - $message_frag_lens) = @_; - - my $self = $class->SUPER::new( - $server, - TLSProxy::Message::MT_HELLO_RETRY_REQUEST, - $data, - $records, - $startoffset, - $message_frag_lens); - - $self->{extension_data} = ""; - - return $self; -} - -sub parse -{ - my $self = shift; - my $ptr = 2; - - TLSProxy::Proxy->is_tls13(1); - - my ($server_version) = unpack('n', $self->data); - # TODO(TLS1.3): Replace this reference to draft version before release - if ($server_version == TLSProxy::Record::VERS_TLS_1_3_DRAFT) { - $server_version = TLSProxy::Record::VERS_TLS_1_3; - } - - my $ciphersuite = unpack('n', substr($self->data, $ptr)); - $ptr += 2; - - my $extensions_len = unpack('n', substr($self->data, $ptr)); - if (!defined $extensions_len) { - $extensions_len = 0; - } - - $ptr += 2; - my $extension_data; - if ($extensions_len != 0) { - $extension_data = substr($self->data, $ptr); - - if (length($extension_data) != $extensions_len) { - die "Invalid extension length\n"; - } - } else { - if (length($self->data) != 2) { - die "Invalid extension length\n"; - } - $extension_data = ""; - } - my %extensions = (); - while (length($extension_data) >= 4) { - my ($type, $size) = unpack("nn", $extension_data); - my $extdata = substr($extension_data, 4, $size); - $extension_data = substr($extension_data, 4 + $size); - $extensions{$type} = $extdata; - } - - $self->server_version($server_version); - $self->ciphersuite($ciphersuite); - $self->extension_data(\%extensions); - - print " Server Version:".$server_version."\n"; - print " Ciphersuite:".$ciphersuite."\n"; - print " Extensions Len:".$extensions_len."\n"; -} - -#Reconstruct the on-the-wire message data following changes -sub set_message_contents -{ - my $self = shift; - my $data; - my $extensions = ""; - - foreach my $key (keys %{$self->extension_data}) { - my $extdata = ${$self->extension_data}{$key}; - $extensions .= pack("n", $key); - $extensions .= pack("n", length($extdata)); - $extensions .= $extdata; - if ($key == TLSProxy::Message::EXT_DUPLICATE_EXTENSION) { - $extensions .= pack("n", $key); - $extensions .= pack("n", length($extdata)); - $extensions .= $extdata; - } - } - - $data = pack('n', $self->server_version); - $data .= pack('n', $self->ciphersuite); - $data .= pack('n', length($extensions)); - $data .= $extensions; - $self->data($data); -} - -#Read/write accessors -sub server_version -{ - my $self = shift; - if (@_) { - $self->{server_version} = shift; - } - return $self->{server_version}; -} -sub ciphersuite -{ - my $self = shift; - if (@_) { - $self->{ciphersuite} = shift; - } - return $self->{ciphersuite}; -} -sub extension_data -{ - my $self = shift; - if (@_) { - $self->{extension_data} = shift; - } - return $self->{extension_data}; -} -sub set_extension -{ - my ($self, $ext_type, $ext_data) = @_; - $self->{extension_data}{$ext_type} = $ext_data; -} -sub delete_extension -{ - my ($self, $ext_type) = @_; - delete $self->{extension_data}{$ext_type}; -} -1; diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm index 1c2bd20..1777e24 100644 --- a/util/perl/TLSProxy/Message.pm +++ b/util/perl/TLSProxy/Message.pm @@ -17,7 +17,6 @@ use constant { MT_CLIENT_HELLO => 1, MT_SERVER_HELLO => 2, MT_NEW_SESSION_TICKET => 4, - MT_HELLO_RETRY_REQUEST => 6, MT_ENCRYPTED_EXTENSIONS => 8, MT_CERTIFICATE => 11, MT_SERVER_KEY_EXCHANGE => 12, @@ -48,7 +47,6 @@ my %message_type = ( MT_CLIENT_HELLO, "ClientHello", MT_SERVER_HELLO, "ServerHello", MT_NEW_SESSION_TICKET, "NewSessionTicket", - MT_HELLO_RETRY_REQUEST, "HelloRetryRequest", MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions", MT_CERTIFICATE, "Certificate", MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange", @@ -172,10 +170,12 @@ sub get_messages #We can't handle this yet die "CCS received before message data complete\n"; } - if ($server) { - TLSProxy::Record->server_encrypting(1); - } else { - TLSProxy::Record->client_encrypting(1); + if (!TLSProxy::Proxy->is_tls13()) { + if ($server) { + TLSProxy::Record->server_encrypting(1); + } else { + TLSProxy::Record->client_encrypting(1); + } } } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) { if ($record->len == 0 || $record->len_real == 0) { @@ -296,15 +296,6 @@ sub create_message [@message_frag_lens] ); $message->parse(); - } elsif ($mt == MT_HELLO_RETRY_REQUEST) { - $message = TLSProxy::HelloRetryRequest->new( - $server, - $data, - [@message_rec_list], - $startoffset, - [@message_frag_lens] - ); - $message->parse(); } elsif ($mt == MT_SERVER_HELLO) { $message = TLSProxy::ServerHello->new( $server, diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm index 83a6494..99b0ded 100644 --- a/util/perl/TLSProxy/Proxy.pm +++ b/util/perl/TLSProxy/Proxy.pm @@ -16,7 +16,6 @@ use IO::Select; use TLSProxy::Record; use TLSProxy::Message; use TLSProxy::ClientHello; -use TLSProxy::HelloRetryRequest; use TLSProxy::ServerHello; use TLSProxy::EncryptedExtensions; use TLSProxy::Certificate; diff --git a/util/perl/TLSProxy/Record.pm b/util/perl/TLSProxy/Record.pm index 5017c90..61ac8e2 100644 --- a/util/perl/TLSProxy/Record.pm +++ b/util/perl/TLSProxy/Record.pm @@ -36,7 +36,7 @@ my %record_type = ( use constant { VERS_TLS_1_4 => 0x0305, - VERS_TLS_1_3_DRAFT => 0x7f15, + VERS_TLS_1_3_DRAFT => 0x7f16, VERS_TLS_1_3 => 0x0304, VERS_TLS_1_2 => 0x0303, VERS_TLS_1_1 => 0x0302, @@ -109,19 +109,21 @@ sub get_records substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real) ); - if (($server && $server_encrypting) - || (!$server && $client_encrypting)) { - if (!TLSProxy::Proxy->is_tls13() && $etm) { - $record->decryptETM(); - } else { - $record->decrypt(); + if ($content_type != RT_CCS) { + if (($server && $server_encrypting) + || (!$server && $client_encrypting)) { + if (!TLSProxy::Proxy->is_tls13() && $etm) { + $record->decryptETM(); + } else { + $record->decrypt(); + } + $record->encrypted(1); + + if (TLSProxy::Proxy->is_tls13()) { + print " Inner content type: " + .$record_type{$record->content_type()}."\n"; + } } - $record->encrypted(1); - } - - if (TLSProxy::Proxy->is_tls13()) { - print " Inner content type: " - .$record_type{$record->content_type()}."\n"; } push @record_list, $record; diff --git a/util/perl/TLSProxy/ServerHello.pm b/util/perl/TLSProxy/ServerHello.pm index 1abdd05..934eaf4 100644 --- a/util/perl/TLSProxy/ServerHello.pm +++ b/util/perl/TLSProxy/ServerHello.pm @@ -12,6 +12,11 @@ package TLSProxy::ServerHello; use vars '@ISA'; push @ISA, 'TLSProxy::Message'; +my $hrrrandom = pack("C*", 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, + 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, + 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, + 0xE2, 0xC8, 0xA8, 0x33, 0x9C); + sub new { my $class = shift; @@ -45,30 +50,23 @@ sub parse my $self = shift; my $ptr = 2; my ($server_version) = unpack('n', $self->data); - - # TODO(TLS1.3): Replace this reference to draft version before release - if ($server_version == TLSProxy::Record::VERS_TLS_1_3_DRAFT) { - $server_version = TLSProxy::Record::VERS_TLS_1_3; - TLSProxy::Proxy->is_tls13(1); - } + my $neg_version = $server_version; my $random = substr($self->data, $ptr, 32); $ptr += 32; my $session_id_len = 0; my $session = ""; - if (!TLSProxy::Proxy->is_tls13()) { - $session_id_len = unpack('C', substr($self->data, $ptr)); - $ptr++; - $session = substr($self->data, $ptr, $session_id_len); - $ptr += $session_id_len; - } + $session_id_len = unpack('C', substr($self->data, $ptr)); + $ptr++; + $session = substr($self->data, $ptr, $session_id_len); + $ptr += $session_id_len; + my $ciphersuite = unpack('n', substr($self->data, $ptr)); $ptr += 2; my $comp_meth = 0; - if (!TLSProxy::Proxy->is_tls13()) { - $comp_meth = unpack('C', substr($self->data, $ptr)); - $ptr++; - } + $comp_meth = unpack('C', substr($self->data, $ptr)); + $ptr++; + my $extensions_len = unpack('n', substr($self->data, $ptr)); if (!defined $extensions_len) { $extensions_len = 0; @@ -96,6 +94,20 @@ sub parse my $extdata = substr($extension_data, 4, $size); $extension_data = substr($extension_data, 4 + $size); $extensions{$type} = $extdata; + if ($type == TLSProxy::Message::EXT_SUPPORTED_VERSIONS) { + $neg_version = unpack('n', $extdata); + } + } + + if ($random eq $hrrrandom) { + TLSProxy::Proxy->is_tls13(1); + # TODO(TLS1.3): Replace this reference to draft version before release + } elsif ($neg_version == TLSProxy::Record::VERS_TLS_1_3_DRAFT) { + $neg_version = TLSProxy::Record::VERS_TLS_1_3; + TLSProxy::Proxy->is_tls13(1); + + TLSProxy::Record->server_encrypting(1); + TLSProxy::Record->client_encrypting(1); } $self->server_version($server_version); @@ -109,10 +121,6 @@ sub parse $self->process_data(); - if (TLSProxy::Proxy->is_tls13()) { - TLSProxy::Record->server_encrypting(1); - TLSProxy::Record->client_encrypting(1); - } print " Server Version:".$server_version."\n"; print " Session ID Len:".$session_id_len."\n"; @@ -138,14 +146,10 @@ sub set_message_contents $data = pack('n', $self->server_version); $data .= $self->random; - if (!TLSProxy::Proxy->is_tls13()) { - $data .= pack('C', $self->session_id_len); - $data .= $self->session; - } + $data .= pack('C', $self->session_id_len); + $data .= $self->session; $data .= pack('n', $self->ciphersuite); - if (!TLSProxy::Proxy->is_tls13()) { - $data .= pack('C', $self->comp_meth); - } + $data .= pack('C', $self->comp_meth); foreach my $key (keys %{$self->extension_data}) { my $extdata = ${$self->extension_data}{$key}; diff --git a/util/perl/checkhandshake.pm b/util/perl/checkhandshake.pm index 65c5135..e1667d5 100644 --- a/util/perl/checkhandshake.pm +++ b/util/perl/checkhandshake.pm @@ -69,10 +69,33 @@ sub checkhandshake($$$$) my $extcount; my $clienthelloseen = 0; + my $lastmt = 0; + my $numsh = 0; + if (TLSProxy::Proxy::is_tls13()) { + #How many ServerHellos are we expecting? + for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) { + next if (($handmessages[$loop][1] & $handtype) == 0); + $numsh++ if ($lastmt != TLSProxy::Message::MT_SERVER_HELLO + && $handmessages[$loop][0] == TLSProxy::Message::MT_SERVER_HELLO); + $lastmt = $handmessages[$loop][0]; + } + } + #First count the number of tests my $nextmess = 0; my $message = undef; my $chnum = 0; + my $shnum = 0; + if (!TLSProxy::Proxy::is_tls13()) { + # In non-TLSv1.3 we always treat reneg CH and SH like the first CH + # and SH + $chnum = 1; + $shnum = 1; + } + #If we're only expecting one ServerHello out of two then we skip the + #first ServerHello in the list completely + $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13()); + $loop = 0; for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) { next if (($handmessages[$loop][1] & $handtype) == 0); if (scalar @{$proxy->message_list} > $nextmess) { @@ -84,10 +107,11 @@ sub checkhandshake($$$$) $numtests++; next if (!defined $message); - $chnum = 1 if $message->mt() != TLSProxy::Message::MT_CLIENT_HELLO - && TLSProxy::Proxy::is_tls13(); + if (TLSProxy::Proxy::is_tls13()) { + $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO; + $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO; + } next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO - && $message->mt() != TLSProxy::Message::MT_HELLO_RETRY_REQUEST && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO && $message->mt() != TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS @@ -96,14 +120,19 @@ sub checkhandshake($$$$) next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE && !TLSProxy::Proxy::is_tls13(); - my $extchnum = 0; + my $extchnum = 1; + my $extshnum = 1; for (my $extloop = 0; $extensions[$extloop][2] != 0; $extloop++) { - $extchnum = 1 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO + $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO && TLSProxy::Proxy::is_tls13(); + $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO + && $extchnum == 2; next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO && $extchnum != $chnum; + next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO + && $extshnum != $shnum; next if ($message->mt() != $extensions[$extloop][0]); $numtests++; } @@ -114,7 +143,18 @@ sub checkhandshake($$$$) $nextmess = 0; $message = undef; - $chnum = 0; + if (TLSProxy::Proxy::is_tls13()) { + $chnum = 0; + $shnum = 0; + } else { + # In non-TLSv1.3 we always treat reneg CH and SH like the first CH + # and SH + $chnum = 1; + $shnum = 1; + } + #If we're only expecting one ServerHello out of two then we skip the + #first ServerHello in the list completely + $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13()); for ($loop = 0; $handmessages[$loop][1] != 0; $loop++) { next if (($handmessages[$loop][1] & $handtype) == 0); if (scalar @{$proxy->message_list} > $nextmess) { @@ -132,11 +172,12 @@ sub checkhandshake($$$$) "Message type check. Got ".$message->mt .", expected ".$handmessages[$loop][0]); } - $chnum = 1 if $message->mt() != TLSProxy::Message::MT_CLIENT_HELLO - && TLSProxy::Proxy::is_tls13(); + if (TLSProxy::Proxy::is_tls13()) { + $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO; + $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO; + } next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO - && $message->mt() != TLSProxy::Message::MT_HELLO_RETRY_REQUEST && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO && $message->mt() != TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS @@ -153,16 +194,21 @@ sub checkhandshake($$$$) } #Now check that we saw the extensions we expected my $msgexts = $message->extension_data(); - my $extchnum = 0; + my $extchnum = 1; + my $extshnum = 1; for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0; $extloop++) { #In TLSv1.3 we can have two ClientHellos if there has been a #HelloRetryRequest, and they may have different extensions. Skip #if these are extensions for a different ClientHello - $extchnum = 1 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO + $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO && TLSProxy::Proxy::is_tls13(); + $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO + && $extchnum == 2; next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO && $extchnum != $chnum; + next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO + && $extshnum != $shnum; next if ($message->mt() != $extensions[$extloop][0]); ok (($extensions[$extloop][2] & $exttype) == 0 || defined ($msgexts->{$extensions[$extloop][1]}), _____ openssl-commits mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-commits