From 05fdae9dc2c63cdd44d89cb98d1ae76360f2a42d Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 12 Apr 2019 11:13:25 -0400 Subject: [PATCH] Add support for BoringSSL QUIC APIs This adds a compatible API for BoringSSL's QUIC support, based on the current |draft-ietf-quic-tls|. Based on BoringSSL commit 3c034b2cf386b3131f75520705491871a2e0cafe Based on BoringSSL commit c8e0f90f83b9ec38ea833deb86b5a41360b62b6a Based on BoringSSL commit 3cbb0299a28a8bd0136257251a78b91a96c5eec8 Based on BoringSSL commit cc9d935256539af2d3b7f831abf57c0d685ffd81 Based on BoringSSL commit e6eef1ca16a022e476bbaedffef044597cfc8f4b Based on BoringSSL commit 6f733791148cf8a076bf0e95498235aadbe5926d Based on BoringSSL commit 384d0eaf1930af1ebc47eda751f0c78dfcba1c03 Based on BoringSSL commit a0373182eb5cc7b81d49f434596b473c7801c942 Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 --- CHANGES | 3 + Configure | 4 +- INSTALL | 3 + crypto/err/openssl.txt | 18 ++ doc/man3/SSL_CIPHER_get_name.pod | 13 ++ doc/man3/SSL_CTX_set_quic_method.pod | 232 +++++++++++++++++++++++++ include/openssl/evp.h | 6 +- include/openssl/ossl_typ.h | 4 +- include/openssl/ssl.h | 47 ++++- include/openssl/sslerr.h | 14 ++ include/openssl/tls1.h | 5 +- ssl/build.info | 3 +- ssl/s3_msg.c | 12 +- ssl/ssl_ciph.c | 34 +++- ssl/ssl_err.c | 4 + ssl/ssl_lib.c | 43 ++++- ssl/ssl_locl.h | 38 +++- ssl/ssl_quic.c | 250 +++++++++++++++++++++++++++ ssl/statem/extensions.c | 31 +++- ssl/statem/extensions_clnt.c | 53 +++++- ssl/statem/extensions_srvr.c | 56 +++++- ssl/statem/statem.c | 23 ++- ssl/statem/statem_lib.c | 21 ++- ssl/statem/statem_locl.h | 21 ++- ssl/statem/statem_quic.c | 110 ++++++++++++ ssl/tls13_enc.c | 61 ++++++- test/sslapitest.c | 133 +++++++++++++- test/ssltestlib.c | 5 + test/tls13secretstest.c | 9 +- util/libssl.num | 11 ++ util/private.num | 2 + 31 files changed, 1243 insertions(+), 26 deletions(-) create mode 100644 doc/man3/SSL_CTX_set_quic_method.pod create mode 100644 ssl/ssl_quic.c create mode 100644 ssl/statem/statem_quic.c diff --git a/CHANGES b/CHANGES index 369b32756cfc5..6297640c60e74 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,9 @@ Changes between 1.1.1 and 3.0.0 [xx XXX xxxx] + *) Implement BoringSSL's QUIC API + [Todd Short] + *) Early start up entropy quality from the DEVRANDOM seed source has been improved for older Linux systems. The RAND subsystem will wait for /dev/random to be producing output before seeding from /dev/urandom. diff --git a/Configure b/Configure index 21bd348d528b7..54617640e1aaa 100755 --- a/Configure +++ b/Configure @@ -1,6 +1,6 @@ #! /usr/bin/env perl # -*- mode: perl; -*- -# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -382,6 +382,7 @@ my @disablables = ( "poly1305", "posix-io", "psk", + "quic", "rc2", "rc4", "rc5", @@ -536,6 +537,7 @@ my @disable_cascades = ( "legacy" => [ "md2" ], "cmp" => [ "crmf" ], + "tls1_3" => [ "quic" ], ); # Avoid protocol support holes. Also disable all versions below N, if version diff --git a/INSTALL b/INSTALL index 9ea1f115138fd..e12a9fe8d0bd3 100644 --- a/INSTALL +++ b/INSTALL @@ -479,6 +479,9 @@ no-psk Don't build support for Pre-Shared Key based ciphersuites. + no-quic + Don't build support for QUIC support. + no-rdrand Don't use hardware RDRAND capabilities. diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 58f6c4894fea0..2a731835da77f 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1356,6 +1356,8 @@ SSL_F_PARSE_CA_NAMES:541:parse_ca_names SSL_F_PITEM_NEW:624:pitem_new SSL_F_PQUEUE_NEW:625:pqueue_new SSL_F_PROCESS_KEY_SHARE_EXT:439:* +SSL_F_QUIC_GET_MESSAGE:640:quic_get_message +SSL_F_QUIC_SET_ENCRYPTION_SECRETS:641:quic_set_encryption_secrets SSL_F_READ_STATE_MACHINE:352:read_state_machine SSL_F_SET_CLIENT_CIPHERSUITE:540:set_client_ciphersuite SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET:595:srp_generate_client_master_secret @@ -1366,7 +1368,9 @@ SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM:130:ssl3_check_cert_and_algorithm SSL_F_SSL3_CTRL:213:ssl3_ctrl SSL_F_SSL3_CTX_CTRL:133:ssl3_ctx_ctrl SSL_F_SSL3_DIGEST_CACHED_RECORDS:293:ssl3_digest_cached_records +SSL_F_SSL3_DISPATCH_ALERT:642:ssl3_dispatch_alert SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC:292:ssl3_do_change_cipher_spec +SSL_F_SSL3_DO_WRITE:643:ssl3_do_write SSL_F_SSL3_ENC:608:ssl3_enc SSL_F_SSL3_FINAL_FINISH_MAC:285:ssl3_final_finish_mac SSL_F_SSL3_FINISH_MAC:587:ssl3_finish_mac @@ -1474,6 +1478,8 @@ SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT:311:* SSL_F_SSL_PEEK:270:SSL_peek SSL_F_SSL_PEEK_EX:432:SSL_peek_ex SSL_F_SSL_PEEK_INTERNAL:522:ssl_peek_internal +SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE:644:SSL_process_quic_post_handshake +SSL_F_SSL_PROVIDE_QUIC_DATA:645:SSL_provide_quic_data SSL_F_SSL_READ:223:SSL_read SSL_F_SSL_READ_EARLY_DATA:529:SSL_read_early_data SSL_F_SSL_READ_EX:434:SSL_read_ex @@ -1524,6 +1530,7 @@ SSL_F_SSL_WRITE_EARLY_DATA:526:SSL_write_early_data SSL_F_SSL_WRITE_EARLY_FINISH:527:* SSL_F_SSL_WRITE_EX:433:SSL_write_ex SSL_F_SSL_WRITE_INTERNAL:524:ssl_write_internal +SSL_F_STATEM_FLUSH:646:statem_flush SSL_F_STATE_MACHINE:353:state_machine SSL_F_TLS12_CHECK_PEER_SIGALG:333:tls12_check_peer_sigalg SSL_F_TLS12_COPY_SIGALGS:533:tls12_copy_sigalgs @@ -1587,6 +1594,8 @@ SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH:619:\ tls_construct_ctos_post_handshake_auth SSL_F_TLS_CONSTRUCT_CTOS_PSK:501:tls_construct_ctos_psk SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES:509:tls_construct_ctos_psk_kex_modes +SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS:647:\ + tls_construct_ctos_quic_transport_params SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE:473:tls_construct_ctos_renegotiate SSL_F_TLS_CONSTRUCT_CTOS_SCT:474:tls_construct_ctos_sct SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME:475:tls_construct_ctos_server_name @@ -1628,6 +1637,8 @@ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE:456:tls_construct_stoc_key_share SSL_F_TLS_CONSTRUCT_STOC_MAXFRAGMENTLEN:548:tls_construct_stoc_maxfragmentlen SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG:457:tls_construct_stoc_next_proto_neg SSL_F_TLS_CONSTRUCT_STOC_PSK:504:tls_construct_stoc_psk +SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS:648:\ + tls_construct_stoc_quic_transport_params SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE:458:tls_construct_stoc_renegotiate SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME:459:tls_construct_stoc_server_name SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET:460:tls_construct_stoc_session_ticket @@ -1656,6 +1667,8 @@ SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN:571:tls_parse_ctos_maxfragmentlen SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH:620:tls_parse_ctos_post_handshake_auth SSL_F_TLS_PARSE_CTOS_PSK:505:tls_parse_ctos_psk SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES:572:tls_parse_ctos_psk_kex_modes +SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS:649:\ + tls_parse_ctos_quic_transport_params SSL_F_TLS_PARSE_CTOS_RENEGOTIATE:464:tls_parse_ctos_renegotiate SSL_F_TLS_PARSE_CTOS_SERVER_NAME:573:tls_parse_ctos_server_name SSL_F_TLS_PARSE_CTOS_SESSION_TICKET:574:tls_parse_ctos_session_ticket @@ -1674,6 +1687,8 @@ SSL_F_TLS_PARSE_STOC_KEY_SHARE:445:tls_parse_stoc_key_share SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN:581:tls_parse_stoc_maxfragmentlen SSL_F_TLS_PARSE_STOC_NPN:582:tls_parse_stoc_npn SSL_F_TLS_PARSE_STOC_PSK:502:tls_parse_stoc_psk +SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS:650:\ + tls_parse_stoc_quic_transport_params SSL_F_TLS_PARSE_STOC_RENEGOTIATE:448:tls_parse_stoc_renegotiate SSL_F_TLS_PARSE_STOC_SCT:564:tls_parse_stoc_sct SSL_F_TLS_PARSE_STOC_SERVER_NAME:583:tls_parse_stoc_server_name @@ -2875,6 +2890,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec SSL_R_BAD_CIPHER:186:bad cipher SSL_R_BAD_DATA:390:bad data +SSL_R_BAD_DATA_LENGTH:294:bad data length SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback SSL_R_BAD_DECOMPRESSION:107:bad decompression SSL_R_BAD_DH_VALUE:102:bad dh value @@ -2981,6 +2997,7 @@ SSL_R_INCONSISTENT_EARLY_DATA_ALPN:222:inconsistent early data alpn 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_INTERNAL_ERROR:295:internal error 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 @@ -3154,6 +3171,7 @@ SSL_R_VERSION_TOO_LOW:396:version too low SSL_R_WRONG_CERTIFICATE_TYPE:383:wrong certificate type SSL_R_WRONG_CIPHER_RETURNED:261:wrong cipher returned SSL_R_WRONG_CURVE:378:wrong curve +SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED:296:wrong encryption level received SSL_R_WRONG_SIGNATURE_LENGTH:264:wrong signature length SSL_R_WRONG_SIGNATURE_SIZE:265:wrong signature size SSL_R_WRONG_SIGNATURE_TYPE:370:wrong signature type diff --git a/doc/man3/SSL_CIPHER_get_name.pod b/doc/man3/SSL_CIPHER_get_name.pod index 26ee6a0fa193e..da14813234c36 100644 --- a/doc/man3/SSL_CIPHER_get_name.pod +++ b/doc/man3/SSL_CIPHER_get_name.pod @@ -13,6 +13,7 @@ SSL_CIPHER_get_digest_nid, SSL_CIPHER_get_handshake_digest, SSL_CIPHER_get_kx_nid, SSL_CIPHER_get_auth_nid, +SSL_CIPHER_get_prf_nid, SSL_CIPHER_is_aead, SSL_CIPHER_find, SSL_CIPHER_get_id, @@ -34,6 +35,7 @@ SSL_CIPHER_get_protocol_id const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c); int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c); int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c); + int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); int SSL_CIPHER_is_aead(const SSL_CIPHER *c); const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c); @@ -91,6 +93,15 @@ TLS 1.3 cipher suites) B is returned. Examples (not comprehensive) NID_auth_ecdsa NID_auth_psk +SSL_CIPHER_get_prf_nid() retuns the pseudo-random function NID for B. If B is +a pre-TLS-1.2 cipher, it returns B but note these ciphers use +SHA-256 in TLS 1.2. Other return values may be treated uniformly in all +applicable versions. Examples (not comprehensive): + + NID_md5_sha1 + NID_sha256 + NID_sha384 + SSL_CIPHER_is_aead() returns 1 if the cipher B is AEAD (e.g. GCM or ChaCha20/Poly1305), and 0 if it is not AEAD. @@ -201,6 +212,8 @@ required to enable this function. The OPENSSL_cipher_name() function was added in OpenSSL 1.1.1. +The SSL_CIPHER_get_prf_nid() function was added in OpenSSL 3.0.0. + =head1 COPYRIGHT Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod new file mode 100644 index 0000000000000..d938eb4e309ca --- /dev/null +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -0,0 +1,232 @@ +=pod + +=head1 NAME + +SSL_QUIC_METHOD, +OSSL_ENCRYPTION_LEVEL, +SSL_CTX_set_quic_method, +SSL_set_quic_method, +SSL_set_quic_transport_params, +SSL_get_peer_quic_transport_params, +SSL_quic_max_handshake_flight_len, +SSL_quic_read_level, +SSL_quic_write_level, +SSL_provide_quic_data, +SSL_process_quic_post_handshake, +SSL_is_quic +- QUIC support + +=head1 SYNOPSIS + + #include + + typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + typedef enum ssl_encryption_level_t OSSL_ENCRYPTION_LEVEL; + + int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method); + int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); + int SSL_set_quic_transport_params(SSL *ssl, + const uint8_t *params, + size_t params_len); + void SSL_get_peer_quic_transport_params(const SSL *ssl, + const uint8_t **out_params, + size_t *out_params_len); + size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level); + OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl); + OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl); + int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); + int SSL_process_quic_post_handshake(SSL *ssl); + int SSL_is_quic(SSL *ssl); + +=head1 DESCRIPTION + +SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods. +This should only be configured with a minimum version of TLS 1.3. B +must remain valid for the lifetime of B or B. Calling this disables +the SSL_OP_ENABLE_MIDDLEBOX_COMPAT option, which is not required for QUIC. + +SSL_set_quic_transport_params() configures B to send B (of length +B) in the quic_transport_parameters extension in either the +ClientHello or EncryptedExtensions handshake message. This extension will +only be sent if the TLS version is at least 1.3, and for a server, only if +the client sent the extension. The buffer pointed to by B only need be +valid for the duration of the call to this function. + +SSL_get_peer_quic_transport_params() provides the caller with the value of the +quic_transport_parameters extension sent by the peer. A pointer to the buffer +containing the TransportParameters will be put in B<*out_params>, and its +length in B<*out_params_len>. This buffer will be valid for the lifetime of the +B. If no params were received from the peer, B<*out_params_len> will be 0. + +SSL_quic_max_handshake_flight_len() returns returns the maximum number of bytes +that may be received at the given encryption level. This function should be +used to limit buffering in the QUIC implementation. + +See https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4. + +SSL_quic_read_level() returns the current read encryption level. + +SSL_quic_write_level() returns the current write encryption level. + +SSL_provide_quic_data() provides data from QUIC at a particular encryption +level B. It is an error to call this function outside of the handshake +or with an encryption level other than the current read level. It returns one +on success and zero on error. + +SSL_process_quic_post_handshake() processes any data that QUIC has provided +after the handshake has completed. This includes NewSessionTicket messages +sent by the server. + +SSL_is_quic() indicates whether a connection uses QUIC. + +=head1 NOTES + +These APIs are implementations of BoringSSL's QUIC APIs. + +QUIC acts as an underlying transport for the TLS 1.3 handshake. The following +functions allow a QUIC implementation to serve as the underlying transport as +described in draft-ietf-quic-tls. + +When configured for QUIC, SSL_do_handshake() will drive the handshake as +before, but it will not use the configured B. It will call functions on +B to configure secrets and send data. If data is needed from +the peer, it will return B. When received, the caller +should call SSL_provide_quic_data() and then SSL_do_handshake() to continue +the handshake. After the handshake is complete, the caller should call +SSL_provide_quic_data() for any post-handshake data, followed by +SSL_process_quic_post_handshake() to process it. It is an error to call +SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC. + +Note that secrets for an encryption level may be available to QUIC before the +level is active in TLS. Callers should use SSL_quic_read_level() to determine +the active read level for SSL_provide_quic_data(). SSL_do_handshake() will +pass the active write level to add_handshake_data() when writing data. Callers +can use SSL_quic_write_level() to query the active write level when +generating their own errors. + +See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more +details. + +To avoid DoS attacks, the QUIC implementation must limit the amount of data +being queued up. The implementation can call +SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each +encryption level. + +draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters +used by QUIC for each endpoint to unilaterally declare its supported +transport parameters. draft-ietf-quic-transport (section 7.4) defines the +contents of that extension (a TransportParameters struct) and describes how +to handle it and its semantic meaning. + +OpenSSL handles this extension as an opaque byte string. The caller is +responsible for serializing and parsing it. + +=head2 OSSL_ENCRYPTION_LEVEL + +B (B) represents the +encryption levels: + +=over 4 + +=item ssl_encryption_initial + +The initial encryption level that is used for client and server hellos. + +=item ssl_encryption_early_data + +The encryption level for early data. This is a write-level for the client +and a read-level for the server. + +=item ssl_encryption_handshake + +The encryption level for the remainder of the handshake. + +=item ssl_encryption_application + +The encryption level for the application data. + +=back + +=head2 SSL_QUIC_METHOD + +The B (B) describes the +QUIC methods. + + struct ssl_quic_method_st { + int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len); + int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); + int (*flush_flight)(SSL *ssl); + int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert); + }; + typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + +set_encryption_secrets() configures the read and write secrets for the given +encryption level. This function will always be called before an encryption +level other than B is used. Note, however, that +secrets for a level may be configured before TLS is ready to send or accept +data at that level. + +When reading packets at a given level, the QUIC implementation must send +ACKs at the same level, so this function provides read and write secrets +together. The exception is B, where secrets are +only available in the client to server direction. The other secret will be +NULL. The server acknowledges such data at B, +which will be configured in the same SSL_do_handshake() call. + +This function should use SSL_get_current_cipher() to determine the TLS +cipher suite. + +add_handshake_data() adds handshake data to the current flight at the given +encryption level. It returns one on success and zero on error. + +OpenSSL will pack data from a single encryption level together, but a +single handshake flight may include multiple encryption levels. Callers +should defer writing data to the network until flush_flight() to better +pack QUIC packets into transport datagrams. + +flush_flight() is called when the current flight is complete and should be +written to the transport. Note a flight may contain data at several +encryption levels. + +send_alert() sends a fatal alert at the specified encryption level. + +All QUIC methods return 1 on success and 0 on error. + +=head1 RETURN VALUES + +SSL_CTX_set_quic_method(), +SSL_set_quic_method(), +SSL_set_quic_transport_params(), and +SSL_process_quic_post_handshake() +return 1 on success, and 0 on error. + +SSL_quic_read_level() and SSL_quic_write_level() return the current +encryption level as B (B). + +SSL_quic_max_handshake_flight_len() returns the maximum length of a flight +for a given encryption level. + +SSL_is_quic() returns 1 if QUIC is being used, 0 if not. + +=head1 SEE ALSO + +L, L, L + +=head1 HISTORY + +These functions were added in OpenSSL 3.0.0. + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/openssl/evp.h b/include/openssl/evp.h index c778ef43dad8e..b6941657b14ef 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1405,6 +1405,10 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth, */ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 +/* Used by Chromium/QUIC */ +# define X25519_PRIVATE_KEY_LEN 32 +# define X25519_PUBLIC_VALUE_LEN 32 + const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags, diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h index 7eec053bee044..d397a750ecfa5 100644 --- a/include/openssl/ossl_typ.h +++ b/include/openssl/ossl_typ.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -193,6 +193,8 @@ typedef struct ossl_item_st OSSL_ITEM; typedef struct ossl_algorithm_st OSSL_ALGORITHM; typedef struct ossl_param_st OSSL_PARAM; +typedef struct ssl_quic_method_st SSL_QUIC_METHOD; + #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ defined(INTMAX_MAX) && defined(UINTMAX_MAX) typedef intmax_t ossl_intmax_t; diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 93f6bbc8f830b..b761231d6b6ef 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -2458,6 +2458,51 @@ void SSL_set_allow_early_data_cb(SSL *s, const char *OSSL_default_cipher_list(void); const char *OSSL_default_ciphersuites(void); +# ifndef OPENSSL_NO_QUIC +/* + * QUIC integration - The QUIC interface matches BoringSSL + * + * ssl_encryption_level_t represents a specific QUIC encryption level used to + * transmit handshake messages. BoringSSL has this as an 'enum'. + */ +typedef enum ssl_encryption_level_t { + ssl_encryption_initial = 0, + ssl_encryption_early_data, + ssl_encryption_handshake, + ssl_encryption_application +} OSSL_ENCRYPTION_LEVEL; + +struct ssl_quic_method_st { + int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len); + int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); + int (*flush_flight)(SSL *ssl); + int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert); +}; + +__owur int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method); +__owur int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); +__owur int SSL_set_quic_transport_params(SSL *ssl, + const uint8_t *params, + size_t params_len); +void SSL_get_peer_quic_transport_params(const SSL *ssl, + const uint8_t **out_params, + size_t *out_params_len); +__owur size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level); +__owur OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl); +__owur OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl); +__owur int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len); +__owur int SSL_process_quic_post_handshake(SSL *ssl); + +__owur int SSL_is_quic(SSL *ssl); + +# endif + +int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); + # ifdef __cplusplus } # endif diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index d8d3cea5d8ef9..453249e926469 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -95,6 +95,8 @@ int ERR_load_SSL_strings(void); # define SSL_F_PITEM_NEW 0 # define SSL_F_PQUEUE_NEW 0 # define SSL_F_PROCESS_KEY_SHARE_EXT 0 +# define SSL_F_QUIC_GET_MESSAGE 0 +# define SSL_F_QUIC_SET_ENCRYPTION_SECRETS 0 # define SSL_F_READ_STATE_MACHINE 0 # define SSL_F_SET_CLIENT_CIPHERSUITE 0 # define SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET 0 @@ -105,7 +107,9 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL3_CTRL 0 # define SSL_F_SSL3_CTX_CTRL 0 # define SSL_F_SSL3_DIGEST_CACHED_RECORDS 0 +# define SSL_F_SSL3_DISPATCH_ALERT 0 # define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 0 +# define SSL_F_SSL3_DO_WRITE 0 # define SSL_F_SSL3_ENC 0 # define SSL_F_SSL3_FINAL_FINISH_MAC 0 # define SSL_F_SSL3_FINISH_MAC 0 @@ -210,6 +214,8 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_PEEK 0 # define SSL_F_SSL_PEEK_EX 0 # define SSL_F_SSL_PEEK_INTERNAL 0 +# define SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE 0 +# define SSL_F_SSL_PROVIDE_QUIC_DATA 0 # define SSL_F_SSL_READ 0 # define SSL_F_SSL_READ_EARLY_DATA 0 # define SSL_F_SSL_READ_EX 0 @@ -260,6 +266,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_WRITE_EARLY_FINISH 0 # define SSL_F_SSL_WRITE_EX 0 # define SSL_F_SSL_WRITE_INTERNAL 0 +# define SSL_F_STATEM_FLUSH 0 # define SSL_F_STATE_MACHINE 0 # define SSL_F_TLS12_CHECK_PEER_SIGALG 0 # define SSL_F_TLS12_COPY_SIGALGS 0 @@ -319,6 +326,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH 0 # define SSL_F_TLS_CONSTRUCT_CTOS_PSK 0 # define SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES 0 +# define SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS 0 # define SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE 0 # define SSL_F_TLS_CONSTRUCT_CTOS_SCT 0 # define SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME 0 @@ -358,6 +366,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_STOC_MAXFRAGMENTLEN 0 # define SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG 0 # define SSL_F_TLS_CONSTRUCT_STOC_PSK 0 +# define SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS 0 # define SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE 0 # define SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME 0 # define SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET 0 @@ -383,6 +392,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH 0 # define SSL_F_TLS_PARSE_CTOS_PSK 0 # define SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES 0 +# define SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS 0 # define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 0 # define SSL_F_TLS_PARSE_CTOS_SERVER_NAME 0 # define SSL_F_TLS_PARSE_CTOS_SESSION_TICKET 0 @@ -401,6 +411,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN 0 # define SSL_F_TLS_PARSE_STOC_NPN 0 # define SSL_F_TLS_PARSE_STOC_PSK 0 +# define SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS 0 # define SSL_F_TLS_PARSE_STOC_RENEGOTIATE 0 # define SSL_F_TLS_PARSE_STOC_SCT 0 # define SSL_F_TLS_PARSE_STOC_SERVER_NAME 0 @@ -463,6 +474,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 # define SSL_R_BAD_CIPHER 186 # define SSL_R_BAD_DATA 390 +# define SSL_R_BAD_DATA_LENGTH 294 # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 # define SSL_R_BAD_DECOMPRESSION 107 # define SSL_R_BAD_DH_VALUE 102 @@ -566,6 +578,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_INCONSISTENT_EARLY_DATA_SNI 231 # define SSL_R_INCONSISTENT_EXTMS 104 # define SSL_R_INSUFFICIENT_SECURITY 241 +# define SSL_R_INTERNAL_ERROR 295 # define SSL_R_INVALID_ALERT 205 # define SSL_R_INVALID_CCS_MESSAGE 260 # define SSL_R_INVALID_CERTIFICATE_OR_ALG 238 @@ -761,6 +774,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_WRONG_CERTIFICATE_TYPE 383 # define SSL_R_WRONG_CIPHER_RETURNED 261 # define SSL_R_WRONG_CURVE 378 +# define SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED 296 # define SSL_R_WRONG_SIGNATURE_LENGTH 264 # define SSL_R_WRONG_SIGNATURE_SIZE 265 # define SSL_R_WRONG_SIGNATURE_TYPE 370 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index f587f2a4887db..4cfa7c64225a3 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -147,6 +147,9 @@ extern "C" { /* Temporary extension type */ # define TLSEXT_TYPE_renegotiate 0xff01 +/* ExtensionType value from draft-ietf-quic-tls-13 */ +# define TLSEXT_TYPE_quic_transport_parameters 0xffa5 + # ifndef OPENSSL_NO_NEXTPROTONEG /* This is not an IANA defined extension number */ # define TLSEXT_TYPE_next_proto_neg 13172 diff --git a/ssl/build.info b/ssl/build.info index 5d70dec6767c6..dd38492c3ab68 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -27,5 +27,6 @@ SOURCE[../libssl]=\ ssl_asn1.c ssl_txt.c ssl_init.c ssl_conf.c ssl_mcnf.c \ bio_ssl.c ssl_err.c tls_srp.c t1_trce.c ssl_utst.c \ record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \ - statem/statem.c record/ssl3_record_tls13.c + statem/statem.c record/ssl3_record_tls13.c \ + ssl_quic.c statem/statem_quic.c DEFINE[../libssl]=$AESDEF diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c index 83778d3a14c25..077b6257a60cd 100644 --- a/ssl/s3_msg.c +++ b/ssl/s3_msg.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -79,6 +79,16 @@ int ssl3_dispatch_alert(SSL *s) s->s3.alert_dispatch = 0; alertlen = 2; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + if (!s->quic_method->send_alert(s, s->quic_write_level, + s->s3.send_alert[1])) { + SSLerr(SSL_F_SSL3_DISPATCH_ALERT, SSL_R_INTERNAL_ERROR); + return 0; + } + i = 1; + } else +#endif i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3.send_alert[0], &alertlen, 1, 0, &written); if (i <= 0) { diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index e427c407fc895..dd8e8b8a8a1e7 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -2193,3 +2193,35 @@ const char *OSSL_default_ciphersuites(void) #endif "TLS_AES_128_GCM_SHA256"; } + +int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c) +{ + switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) { + default: + break; + case TLS1_PRF_SHA1_MD5: /* TLS1_PRF */ + return NID_md5_sha1; + case TLS1_PRF_SHA256: + return NID_sha256; + case TLS1_PRF_SHA384: + return NID_sha384; + case TLS1_PRF_GOST94: + return NID_id_GostR3411_94_prf; + case TLS1_PRF_GOST12_256: + return NID_id_GostR3411_2012_256; + case TLS1_PRF_GOST12_512: + return NID_id_GostR3411_2012_512; + } + /* TLSv1.3 ciphers don't specify separate PRF */ + switch (c->algorithm2 & SSL_HANDSHAKE_MAC_MASK) { + default: + break; + case SSL_HANDSHAKE_MAC_MD5_SHA1: /* SSL_HANDSHAKE_MAC_DEFAULT */ + return NID_md5_sha1; + case SSL_HANDSHAKE_MAC_SHA256: + return NID_sha256; + case SSL_HANDSHAKE_MAC_SHA384: + return NID_sha384; + } + return NID_undef; +} diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index ef9b95a0c9a48..79be69439d31f 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -28,6 +28,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "bad change cipher spec"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), "bad data returned by callback"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"}, @@ -193,6 +194,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EXTMS), "inconsistent extms"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INSUFFICIENT_SECURITY), "insufficient security"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INTERNAL_ERROR), "internal error"}, {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"}, @@ -532,6 +534,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED), "wrong cipher returned"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED), + "wrong encryption level received"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH), "wrong signature length"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE), diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 0d40ecaec9c52..7e113d0e7a3e5 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -844,6 +844,10 @@ SSL *SSL_new(SSL_CTX *ctx) s->job = NULL; +#ifndef OPENSSL_NO_QUIC + s->quic_method = ctx->quic_method; +#endif + #ifndef OPENSSL_NO_CT if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback, ctx->ct_validation_callback_arg)) @@ -1213,6 +1217,18 @@ void SSL_free(SSL *s) OPENSSL_free(s->pha_context); EVP_MD_CTX_free(s->pha_dgst); +#ifndef OPENSSL_NO_QUIC + OPENSSL_free(s->ext.quic_transport_params); + OPENSSL_free(s->ext.peer_quic_transport_params); + while (s->quic_input_data_head != NULL) { + QUIC_DATA *qd; + + qd = s->quic_input_data_head; + s->quic_input_data_head = qd->next; + OPENSSL_free(qd); + } +#endif + sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free); sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free); @@ -1789,6 +1805,12 @@ static int ssl_io_intern(void *vargs) int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (s->handshake_func == NULL) { SSLerr(SSL_F_SSL_READ_INTERNAL, SSL_R_UNINITIALIZED); return -1; @@ -1921,6 +1943,12 @@ int SSL_get_early_data_status(const SSL *s) static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (s->handshake_func == NULL) { SSLerr(SSL_F_SSL_PEEK_INTERNAL, SSL_R_UNINITIALIZED); return -1; @@ -1981,6 +2009,12 @@ int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes) int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (s->handshake_func == NULL) { SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_UNINITIALIZED); return -1; @@ -3641,6 +3675,11 @@ int SSL_get_error(const SSL *s, int i) } if (SSL_want_read(s)) { +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + return SSL_ERROR_WANT_READ; + } +#endif bio = SSL_get_rbio(s); if (BIO_should_read(bio)) return SSL_ERROR_WANT_READ; @@ -4019,7 +4058,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { - if ((s->session != NULL) && (s->session->cipher != NULL)) + if (s->session != NULL) return s->session->cipher; return NULL; } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index b66979b4dad0e..225a74299875a 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * @@ -319,6 +319,13 @@ /* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */ # define SSL3_CK_CIPHERSUITE_FLAG 0x03000000 +/* Check if an SSL structure is using QUIC (which uses TLSv1.3) */ +# ifndef OPENSSL_NO_QUIC +# define SSL_IS_QUIC(s) (s->quic_method != NULL) +# else +# define SSL_IS_QUIC(s) 0 +# endif + /* Check if an SSL structure is using DTLS */ # define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) @@ -719,6 +726,7 @@ typedef enum tlsext_index_en { TLSEXT_IDX_cryptopro_bug, TLSEXT_IDX_early_data, TLSEXT_IDX_certificate_authorities, + TLSEXT_IDX_quic_transport_params, TLSEXT_IDX_padding, TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ @@ -1073,10 +1081,23 @@ struct ssl_ctx_st { /* Callback for SSL async handling */ SSL_async_callback_fn async_cb; void *async_cb_arg; +#ifndef OPENSSL_NO_QUIC + const SSL_QUIC_METHOD *quic_method; +#endif }; typedef struct cert_pkey_st CERT_PKEY; +#ifndef OPENSSL_NO_QUIC +struct quic_data_st { + struct quic_data_st *next; + OSSL_ENCRYPTION_LEVEL level; + size_t length; +}; +typedef struct quic_data_st QUIC_DATA; +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); +#endif + struct ssl_st { /* * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, @@ -1548,8 +1569,23 @@ struct ssl_st { * selected. */ int tick_identity; + +#ifndef OPENSSL_NO_QUIC + uint8_t *quic_transport_params; + size_t quic_transport_params_len; + uint8_t *peer_quic_transport_params; + size_t peer_quic_transport_params_len; +#endif } ext; +#ifndef OPENSSL_NO_QUIC + OSSL_ENCRYPTION_LEVEL quic_read_level; + OSSL_ENCRYPTION_LEVEL quic_write_level; + QUIC_DATA *quic_input_data_head; + QUIC_DATA *quic_input_data_tail; + const SSL_QUIC_METHOD *quic_method; + size_t quic_len; +#endif /* * Parsed form of the ClientHello, kept around across client_hello_cb * calls. diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c new file mode 100644 index 0000000000000..3e1e1ea9068fe --- /dev/null +++ b/ssl/ssl_quic.c @@ -0,0 +1,250 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (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 "ssl_locl.h" +#include "internal/cryptlib.h" +#include "internal/refcount.h" + +#ifdef OPENSSL_NO_QUIC +NON_EMPTY_TRANSLATION_UNIT +#else + +int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, + size_t params_len) +{ + uint8_t *tmp; + + if (params == NULL || params_len == 0) { + tmp = NULL; + params_len = 0; + } else { + tmp = OPENSSL_memdup(params, params_len); + if (tmp == NULL) + return 0; + } + + OPENSSL_free(ssl->ext.quic_transport_params); + ssl->ext.quic_transport_params = tmp; + ssl->ext.quic_transport_params_len = params_len; + return 1; +} + +void SSL_get_peer_quic_transport_params(const SSL *ssl, + const uint8_t **out_params, + size_t *out_params_len) +{ + *out_params = ssl->ext.peer_quic_transport_params; + *out_params_len = ssl->ext.peer_quic_transport_params_len; +} + +size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + /* + * Limits flights to 16K by default when there are no large + * (certificate-carrying) messages. + */ + static const size_t DEFAULT_FLIGHT_LIMIT = 16384; + + switch (level) { + case ssl_encryption_initial: + return DEFAULT_FLIGHT_LIMIT; + case ssl_encryption_early_data: + /* QUIC does not send EndOfEarlyData. */ + return 0; + case ssl_encryption_handshake: + if (ssl->server) { + /* + * Servers may receive Certificate message if configured to request + * client certificates. + */ + if ((ssl->verify_mode & SSL_VERIFY_PEER) + && ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT) + return ssl->max_cert_list; + } else { + /* + * Clients may receive both Certificate message and a CertificateRequest + * message. + */ + if (2*ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT) + return 2 * ssl->max_cert_list; + } + return DEFAULT_FLIGHT_LIMIT; + case ssl_encryption_application: + return DEFAULT_FLIGHT_LIMIT; + } + + return 0; +} + +OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl) +{ + return ssl->quic_read_level; +} + +OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl) +{ + return ssl->quic_write_level; +} + +int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len) +{ + size_t l; + + if (!SSL_IS_QUIC(ssl)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + /* Level can be different than the current read, but not less */ + if (level < ssl->quic_read_level + || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + return 0; + } + + /* Split the QUIC messages up, if necessary */ + while (len > 0) { + QUIC_DATA *qd; + const uint8_t *p = data + 1; + + n2l3(p, l); + l += SSL3_HM_HEADER_LENGTH; + + if (l > len) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH); + return 0; + } + + qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l); + if (qd == NULL) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR); + return 0; + } + + qd->next = NULL; + qd->length = l; + qd->level = level; + memcpy((void*)(qd + 1), data, l); + if (ssl->quic_input_data_tail != NULL) + ssl->quic_input_data_tail->next = qd; + else + ssl->quic_input_data_head = qd; + ssl->quic_input_data_tail = qd; + + data += l; + len -= l; + } + + return 1; +} + +int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) +{ + switch (ctx->method->version) { + case DTLS1_VERSION: + case DTLS1_2_VERSION: + case DTLS_ANY_VERSION: + case DTLS1_BAD_VER: + return 0; + default: + break; + } + ctx->quic_method = quic_method; + ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + return 1; +} + +int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) +{ + switch (ssl->method->version) { + case DTLS1_VERSION: + case DTLS1_2_VERSION: + case DTLS_ANY_VERSION: + case DTLS1_BAD_VER: + return 0; + default: + break; + } + ssl->quic_method = quic_method; + ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + return 1; +} + +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + uint8_t *read_secret = NULL; + uint8_t *write_secret = NULL; + static const unsigned char zeros[EVP_MAX_MD_SIZE]; + + if (!SSL_IS_QUIC(ssl)) + return 1; + + /* secrets from the POV of the client */ + switch (level) { + case ssl_encryption_early_data: + write_secret = ssl->early_secret; + break; + case ssl_encryption_handshake: + read_secret = ssl->client_finished_secret; + write_secret = ssl->server_finished_secret; + break; + case ssl_encryption_application: + read_secret = ssl->client_app_traffic_secret; + write_secret = ssl->server_app_traffic_secret; + break; + default: + return 1; + } + /* In some cases, we want to set the secret only when BOTH are non-zero */ + if (read_secret != NULL && write_secret != NULL + && !memcmp(read_secret, zeros, ssl->quic_len) + && !memcmp(write_secret, zeros, ssl->quic_len)) + return 1; + + if (ssl->server) { + if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, + write_secret, ssl->quic_len)) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_SET_ENCRYPTION_SECRETS, + ERR_R_INTERNAL_ERROR); + return 0; + } + } else { + if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, + read_secret, ssl->quic_len)) { + SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_SET_ENCRYPTION_SECRETS, + ERR_R_INTERNAL_ERROR); + return 0; + } + } + + return 1; +} + +int SSL_process_quic_post_handshake(SSL *ssl) +{ + if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { + SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + ossl_statem_set_in_init(ssl, 1); + + if (ssl->handshake_func(ssl) <= 0) + return 0; + + return 1; +} + +int SSL_is_quic(SSL* ssl) +{ + return SSL_IS_QUIC(ssl); +} + +#endif diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 68163a20aa251..ff3b706b32a69 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -54,6 +54,10 @@ static int final_sig_algs(SSL *s, unsigned int context, int sent); static int final_early_data(SSL *s, unsigned int context, int sent); static int final_maxfragmentlen(SSL *s, unsigned int context, int sent); static int init_post_handshake_auth(SSL *s, unsigned int context); +#ifndef OPENSSL_NO_QUIC +static int init_quic_transport_params(SSL *s, unsigned int context); +static int final_quic_transport_params(SSL *s, unsigned int context, int sent); +#endif /* Structure to define a built-in extension */ typedef struct extensions_definition_st { @@ -372,6 +376,19 @@ static const EXTENSION_DEFINITION ext_defs[] = { tls_construct_certificate_authorities, tls_construct_certificate_authorities, NULL, }, +#ifndef OPENSSL_NO_QUIC + { + TLSEXT_TYPE_quic_transport_parameters, + SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO + | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, + init_quic_transport_params, + tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params, + tls_construct_stoc_quic_transport_params, tls_construct_ctos_quic_transport_params, + final_quic_transport_params, + }, +#else + INVALID_EXTENSION, +#endif { /* Must be immediately before pre_shared_key */ TLSEXT_TYPE_padding, @@ -1698,3 +1715,15 @@ static int init_post_handshake_auth(SSL *s, unsigned int context) return 1; } + +#ifndef OPENSSL_NO_QUIC +static int init_quic_transport_params(SSL *s, unsigned int context) +{ + return 1; +} + +static int final_quic_transport_params(SSL *s, unsigned int context, int sent) +{ + return 1; +} +#endif diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index e6b674cebef90..de0ccfa2f93c1 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1254,7 +1254,30 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, #endif } +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_construct_stoc_quic_transport_params() */ +EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + if (s->ext.quic_transport_params == NULL + || s->ext.quic_transport_params_len == 0) { + return EXT_RETURN_NOT_SENT; + } + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} +#endif /* * Parse the server's renegotiation binding and abort if it's not right */ @@ -2041,3 +2064,31 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 1; } +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_parse_ctos_quic_transport_params() */ +int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + PACKET trans_param; + + if (!PACKET_as_length_prefixed_2(pkt, &trans_param) + || PACKET_remaining(&trans_param) == 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS, + SSL_R_BAD_EXTENSION); + return 0; + } + + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + + if (!PACKET_memdup(&trans_param, + &s->ext.peer_quic_transport_params, + &s->ext.peer_quic_transport_params_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} +#endif diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index e16722cbeb8d6..0f99517de1f63 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1301,6 +1301,35 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, unsigned int context return 1; } +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_parse_stoc_quic_transport_params() */ +int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + PACKET trans_param; + + if (!PACKET_as_length_prefixed_2(pkt, &trans_param) + || PACKET_remaining(&trans_param) == 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS, + SSL_R_BAD_EXTENSION); + return 0; + } + + OPENSSL_free(s->ext.peer_quic_transport_params); + s->ext.peer_quic_transport_params = NULL; + s->ext.peer_quic_transport_params_len = 0; + + if (!PACKET_memdup(&trans_param, + &s->ext.peer_quic_transport_params, + &s->ext.peer_quic_transport_params_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS, ERR_R_INTERNAL_ERROR); + return 0; + } + return 1; +} +#endif + /* * Add the server's renegotiation binding */ @@ -1961,3 +1990,28 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_SENT; } + +#ifndef OPENSSL_NO_QUIC +/* SAME AS tls_construct_ctos_quic_transport_params() */ +EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + if (s->ext.quic_transport_params == NULL + || s->ext.quic_transport_params_len == 0) { + return EXT_RETURN_NOT_SENT; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, + s->ext.quic_transport_params_len) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + return EXT_RETURN_SENT; +} +#endif diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index bd9277b71ec32..ea38b3a68b275 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -576,6 +576,10 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) * In DTLS we get the whole message in one go - header and body */ ret = dtls_get_message(s, &mt, &len); +#ifndef OPENSSL_NO_QUIC + } else if (SSL_IS_QUIC(s)) { + ret = quic_get_message(s, &mt, &len); +#endif } else { ret = tls_get_message_header(s, &mt); } @@ -605,8 +609,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) return SUB_STATE_ERROR; } - /* dtls_get_message already did this */ - if (!SSL_IS_DTLS(s) + /* dtls_get_message/quic_get_message already did this */ + if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s) && s->s3.tmp.message_size > 0 && !grow_init_buf(s, s->s3.tmp.message_size + SSL3_HM_HEADER_LENGTH)) { @@ -619,8 +623,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) /* Fall through */ case READ_STATE_BODY: - if (!SSL_IS_DTLS(s)) { - /* We already got this above for DTLS */ + if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s)) { + /* We already got this above for DTLS & QUIC */ ret = tls_get_message_body(s, &len); if (ret == 0) { /* Could be non-blocking IO */ @@ -901,6 +905,15 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) int statem_flush(SSL *s) { s->rwstate = SSL_WRITING; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + if (!s->quic_method->flush_flight(s)) { + /* NOTE: BIO_flush() does not generate an error */ + SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); + return 0; + } + } else +#endif if (BIO_flush(s->wbio) <= 0) { return 0; } diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 4d3808c559eec..8af2c3a6cd953 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -43,9 +43,23 @@ int ssl3_do_write(SSL *s, int type) { int ret; size_t written = 0; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) { + ret = s->quic_method->add_handshake_data(s, s->quic_write_level, + (const uint8_t*)&s->init_buf->data[s->init_off], + s->init_num); + if (!ret) { + ret = -1; + /* QUIC can't sent anything out sice the above failed */ + SSLerr(SSL_F_SSL3_DO_WRITE, SSL_R_INTERNAL_ERROR); + } else { + written = s->init_num; + } + } else +#endif + ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], + s->init_num, &written); - ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], - s->init_num, &written); if (ret < 0) return -1; if (type == SSL3_RT_HANDSHAKE) @@ -1150,6 +1164,7 @@ int tls_get_message_header(SSL *s, int *mt) do { while (s->init_num < SSL3_HM_HEADER_LENGTH) { + /* QUIC: either create a special ssl_read_bytes... or if/else this */ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index f4242fa2a4410..0134aa4757b71 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -93,6 +93,7 @@ WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst); __owur int tls_get_message_header(SSL *s, int *mt); __owur int tls_get_message_body(SSL *s, size_t *len); __owur int dtls_get_message(SSL *s, int *mt, size_t *len); +__owur int quic_get_message(SSL *s, int *mt, size_t *len); /* Message construction and processing functions */ __owur int tls_process_initial_server_flight(SSL *s); @@ -236,6 +237,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_QUIC +int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); +#endif EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, @@ -298,6 +303,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, size_t chainidx); EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_QUIC +EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); +#endif /* Client Extension processing */ EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context, @@ -369,6 +379,11 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_QUIC +EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); +#endif int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); @@ -414,6 +429,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_QUIC +int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); +#endif int tls_handle_alpn(SSL *s); diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c new file mode 100644 index 0000000000000..80d5406b1a4bc --- /dev/null +++ b/ssl/statem/statem_quic.c @@ -0,0 +1,110 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (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 "../ssl_locl.h" +#include "statem_locl.h" +#include "internal/cryptlib.h" + +#ifdef OPENSSL_NO_QUIC +NON_EMPTY_TRANSLATION_UNIT +#else + +int quic_get_message(SSL *s, int *mt, size_t *len) +{ + size_t l; + QUIC_DATA *qd; + uint8_t *p; + + if (s->quic_input_data_head == NULL) { + s->rwstate = SSL_READING; + *len = 0; + return 0; + } + + /* This is where we check for the proper level, not when data is given */ + if (s->quic_input_data_head->level != s->quic_read_level) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_GET_MESSAGE, + SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + *len = 0; + return 0; + } + + if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_GET_MESSAGE, + ERR_R_BUF_LIB); + *len = 0; + return 0; + } + + /* Copy buffered data */ + qd = s->quic_input_data_head; + memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); + s->init_buf->length = qd->length; + s->quic_input_data_head = qd->next; + if (s->quic_input_data_head == NULL) + s->quic_input_data_tail = NULL; + OPENSSL_free(qd); + + s->s3.tmp.message_type = *mt = *(s->init_buf->data); + p = (uint8_t*)s->init_buf->data + 1; + n2l3(p, l); + s->init_num = s->s3.tmp.message_size = *len = l; + s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; + + /* No CCS in QUIC/TLSv1.3? */ + if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, + SSL_F_QUIC_GET_MESSAGE, + SSL_R_CCS_RECEIVED_EARLY); + *len = 0; + return 0; + } + + /* + * If receiving Finished, record MAC of prior handshake messages for + * Finished verification. + */ + if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { + /* SSLfatal() already called */ + *len = 0; + return 0; + } + + /* + * We defer feeding in the HRR until later. We'll do it as part of + * processing the message + * The TLsv1.3 handshake transcript stops at the ClientFinished + * message. + */ +#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2) + /* KeyUpdate and NewSessionTicket do not need to be added */ + if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET + && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) { + 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, + (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + + return 1; +} + +#endif diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index a238d6e1c6594..f30c4cb88ac1d 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -461,6 +461,9 @@ int tls13_change_cipher_state(SSL *s, int which) int ret = 0; const EVP_MD *md = NULL; const EVP_CIPHER *cipher = NULL; +#ifndef OPENSSL_NO_QUIC + OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; +#endif if (which & SSL3_CC_READ) { if (s->enc_read_ctx != NULL) { @@ -508,6 +511,9 @@ int tls13_change_cipher_state(SSL *s, int which) label = client_early_traffic; labellen = sizeof(client_early_traffic) - 1; log_label = CLIENT_EARLY_LABEL; +#ifndef OPENSSL_NO_QUIC + level = ssl_encryption_early_data; +#endif handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); if (handlen <= 0) { @@ -563,6 +569,9 @@ int tls13_change_cipher_state(SSL *s, int which) goto err; } hashlen = hashlenui; +#ifndef OPENSSL_NO_QUIC + s->quic_len = hashlen; +#endif EVP_MD_CTX_free(mdctx); if (!tls13_hkdf_expand(s, md, insecret, @@ -581,6 +590,14 @@ int tls13_change_cipher_state(SSL *s, int which) /* SSLfatal() already called */ goto err; } +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + if (s->server) + s->quic_read_level = ssl_encryption_early_data; + else + s->quic_write_level = ssl_encryption_early_data; + } +#endif } else if (which & SSL3_CC_HANDSHAKE) { insecret = s->handshake_secret; finsecret = s->client_finished_secret; @@ -588,6 +605,15 @@ int tls13_change_cipher_state(SSL *s, int which) label = client_handshake_traffic; labellen = sizeof(client_handshake_traffic) - 1; log_label = CLIENT_HANDSHAKE_LABEL; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_handshake; + if (s->server) + s->quic_read_level = ssl_encryption_handshake; + else + s->quic_write_level = ssl_encryption_handshake; + } +#endif /* * The handshake hash used for the server read/client write handshake * traffic secret is the same as the hash for the server @@ -610,6 +636,15 @@ int tls13_change_cipher_state(SSL *s, int which) * previously saved value. */ hash = s->server_finished_hash; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_application; /* ??? */ + if (s->server) + s->quic_read_level = ssl_encryption_application; + else + s->quic_write_level = ssl_encryption_application; + } +#endif } } else { /* Early data never applies to client-read/server-write */ @@ -620,11 +655,29 @@ int tls13_change_cipher_state(SSL *s, int which) label = server_handshake_traffic; labellen = sizeof(server_handshake_traffic) - 1; log_label = SERVER_HANDSHAKE_LABEL; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_handshake; + if (s->server) + s->quic_write_level = ssl_encryption_handshake; + else + s->quic_read_level = ssl_encryption_handshake; + } +#endif } else { insecret = s->master_secret; label = server_application_traffic; labellen = sizeof(server_application_traffic) - 1; log_label = SERVER_APPLICATION_LABEL; +#ifndef OPENSSL_NO_QUIC + if (SSL_IS_QUIC(s)) { + level = ssl_encryption_application; + if (s->server) + s->quic_write_level = ssl_encryption_application; + else + s->quic_read_level = ssl_encryption_application; + } +#endif } } @@ -706,6 +759,12 @@ int tls13_change_cipher_state(SSL *s, int which) s->statem.enc_write_state = ENC_WRITE_STATE_WRITE_PLAIN_ALERTS; else s->statem.enc_write_state = ENC_WRITE_STATE_VALID; + +#ifndef OPENSSL_NO_QUIC + if (!quic_set_encryption_secrets(s, level)) + goto err; +#endif + ret = 1; err: OPENSSL_cleanse(secret, sizeof(secret)); diff --git a/test/sslapitest.c b/test/sslapitest.c index 4b510eb3f7fed..0313b56e87a7c 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -6822,6 +6822,134 @@ static int test_ca_names(int tst) return testresult; } +#ifndef OPENSSL_NO_QUIC + +static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, + const uint8_t *write_secret, size_t secret_len) +{ + test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", + ssl->server ? "server" : "client", level, secret_len); + return 1; +} +static int test_quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len) +{ + SSL *peer = (SSL*)SSL_get_app_data(ssl); + + test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", + ssl->server ? "server" : "client", level, (int)*data, len); + if (!TEST_ptr(peer)) + return 0; + + if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) { + ERR_print_errors_fp(stderr); + return 0; + } + + return 1; +} +static int test_quic_flush_flight(SSL *ssl) +{ + test_printf_stderr("quic_flush_flight() %s\n", ssl->server ? "server" : "client"); + return 1; +} +static int test_quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) +{ + test_printf_stderr("quic_send_alert() %s, lvl=%d, alert=%d\n", + ssl->server ? "server" : "client", level, alert); + return 1; +} + +static SSL_QUIC_METHOD quic_method = { + test_quic_set_encryption_secrets, + test_quic_add_handshake_data, + test_quic_flush_flight, + test_quic_send_alert, +}; +static int test_quic_api(void) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + static const char *server_str = "SERVER"; + static const char *client_str = "CLIENT"; + const uint8_t *peer_str; + size_t peer_str_len; + + /* Clean up logging space */ + memset(client_log_buffer, 0, sizeof(client_log_buffer)); + memset(server_log_buffer, 0, sizeof(server_log_buffer)); + client_log_buffer_index = 0; + server_log_buffer_index = 0; + error_writing_log = 0; + + + if (!TEST_ptr(sctx = SSL_CTX_new(TLS_server_method())) + || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) + || !TEST_ptr(sctx->quic_method) + || !TEST_ptr(serverssl = SSL_new(sctx)) + || !TEST_true(SSL_IS_QUIC(serverssl)) + || !TEST_true(SSL_set_quic_method(serverssl, NULL)) + || !TEST_false(SSL_IS_QUIC(serverssl)) + || !TEST_true(SSL_set_quic_method(serverssl, &quic_method)) + || !TEST_true(SSL_IS_QUIC(serverssl))) + goto end; + + SSL_CTX_free(sctx); + sctx = NULL; + SSL_free(serverssl); + serverssl = NULL; + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), + TLS_client_method(), + TLS1_3_VERSION, 0, + &sctx, &cctx, cert, privkey)) + || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) + || !TEST_true(SSL_CTX_set_quic_method(cctx, &quic_method)) + || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, + &clientssl, NULL, NULL)) + || !TEST_true(SSL_set_quic_transport_params(serverssl, + (unsigned char*)server_str, + sizeof(server_str))) + || !TEST_true(SSL_set_quic_transport_params(clientssl, + (unsigned char*)client_str, + sizeof(client_str))) + || !TEST_true(SSL_set_app_data(serverssl, clientssl)) + || !TEST_true(SSL_set_app_data(clientssl, serverssl)) + || !TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE)) + || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) + || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) + || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) + || !(TEST_int_eq(SSL_quic_read_level(serverssl), ssl_encryption_application)) + || !(TEST_int_eq(SSL_quic_write_level(clientssl), ssl_encryption_application)) + || !(TEST_int_eq(SSL_quic_write_level(serverssl), ssl_encryption_application))) + goto end; + + SSL_get_peer_quic_transport_params(serverssl, &peer_str, &peer_str_len); + if (!TEST_mem_eq(peer_str, peer_str_len, client_str, sizeof(client_str))) + goto end; + SSL_get_peer_quic_transport_params(clientssl, &peer_str, &peer_str_len); + if (!TEST_mem_eq(peer_str, peer_str_len, server_str, sizeof(server_str))) + goto end; + + /* Deal with two NewSessionTickets */ + if (!TEST_true(SSL_process_quic_post_handshake(clientssl)) + || !TEST_true(SSL_process_quic_post_handshake(clientssl))) + goto end; + + testresult = 1; + +end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} +#endif OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile\n") @@ -6970,6 +7098,9 @@ int setup_tests(void) ADD_ALL_TESTS(test_cert_cb, 6); ADD_ALL_TESTS(test_client_cert_cb, 2); ADD_ALL_TESTS(test_ca_names, 3); +#ifndef OPENSSL_NO_QUIC + ADD_TEST(test_quic_api); +#endif return 1; } diff --git a/test/ssltestlib.c b/test/ssltestlib.c index 67d8cd0284c5d..9e9f6c51e23cb 100644 --- a/test/ssltestlib.c +++ b/test/ssltestlib.c @@ -1033,6 +1033,11 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) if (!create_bare_ssl_connection(serverssl, clientssl, want, 1)) return 0; +#ifndef OPENSSL_NO_QUIC + /* QUIC does not support SSL_read_ex */ + if (SSL_is_quic(clientssl)) + return 1; +#endif /* * We attempt to read some data on the client side which we expect to fail. * This will ensure we have received the NewSessionTicket in TLSv1.3 where diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c index 4756faac0034a..1bb94032bbdd3 100644 --- a/test/tls13secretstest.c +++ b/test/tls13secretstest.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -206,6 +206,13 @@ int ossl_statem_export_early_allowed(SSL *s) return 1; } +#ifndef OPENSSL_NO_QUIC +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + return 1; +} +#endif + /* End of mocked out code */ static int test_secret(SSL *s, unsigned char *prk, diff --git a/util/libssl.num b/util/libssl.num index 25e12ab36af35..972d25a7213dd 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -506,3 +506,14 @@ SSL_get_async_status 506 3_0_0 EXIST::FUNCTION: SSL_sendfile 507 3_0_0 EXIST::FUNCTION: OSSL_default_cipher_list 508 3_0_0 EXIST::FUNCTION: OSSL_default_ciphersuites 509 3_0_0 EXIST::FUNCTION: +SSL_set_quic_transport_params 510 3_0_0 EXIST::FUNCTION:QUIC +SSL_get_peer_quic_transport_params 511 3_0_0 EXIST::FUNCTION:QUIC +SSL_quic_max_handshake_flight_len 512 3_0_0 EXIST::FUNCTION:QUIC +SSL_quic_read_level 513 3_0_0 EXIST::FUNCTION:QUIC +SSL_quic_write_level 514 3_0_0 EXIST::FUNCTION:QUIC +SSL_provide_quic_data 515 3_0_0 EXIST::FUNCTION:QUIC +SSL_CTX_set_quic_method 516 3_0_0 EXIST::FUNCTION:QUIC +SSL_set_quic_method 517 3_0_0 EXIST::FUNCTION:QUIC +SSL_process_quic_post_handshake 518 3_0_0 EXIST::FUNCTION:QUIC +SSL_CIPHER_get_prf_nid 519 3_0_0 EXIST::FUNCTION: +SSL_is_quic 520 3_0_0 EXIST::FUNCTION:QUIC diff --git a/util/private.num b/util/private.num index 351828268c7a9..8015030b10ade 100644 --- a/util/private.num +++ b/util/private.num @@ -99,6 +99,8 @@ pem_password_cb datatype ssl_ct_validation_cb datatype ASYNC_callback_fn datatype SSL_async_callback_fn datatype +OSSL_ENCRYPTION_LEVEL datatype +SSL_QUIC_METHOD datatype # BIO_append_filename define BIO_destroy_bio_pair define