/* * Copyright 2022-2024 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 #include "internal/recordmethod.h" #include "internal/quic_tls.h" #include "../ssl_local.h" #include "internal/quic_error.h" #define QUIC_TLS_FATAL(rl, ad, err) \ do { \ if ((rl) != NULL) (rl)->alert = (ad); \ ERR_raise(ERR_LIB_SSL, (err)); \ if ((rl) != NULL) (rl)->qtls->inerror = 1; \ } while(0) struct quic_tls_st { QUIC_TLS_ARGS args; /* * Transport parameters which client should send. Buffer lifetime must * exceed the lifetime of the QUIC_TLS object. */ const unsigned char *local_transport_params; size_t local_transport_params_len; ERR_STATE *error_state; /* * QUIC error code (usually in the TLS Alert-mapped CRYPTO_ERR range). Valid * only if inerror is 1. */ uint64_t error_code; /* * Error message with static storage duration. Valid only if inerror is 1. * Should be suitable for encapsulation in a CONNECTION_CLOSE frame. */ const char *error_msg; /* Whether our SSL object for TLS has been configured for use in QUIC */ unsigned int configured : 1; /* Set if we have hit any error state */ unsigned int inerror : 1; /* Set if the handshake has completed */ unsigned int complete : 1; }; struct ossl_record_layer_st { QUIC_TLS *qtls; /* Protection level */ int level; /* Only used for retry flags */ BIO *dummybio; /* Number of bytes written so far if we are part way through a write */ size_t written; /* If we are part way through a write, a copy of the template */ OSSL_RECORD_TEMPLATE template; /* * If we hit an error, what alert code should be used */ int alert; /* Amount of crypto stream data we read in the last call to quic_read_record */ size_t recread; /* Amount of crypto stream data read but not yet released */ size_t recunreleased; /* Callbacks */ OSSL_FUNC_rlayer_msg_callback_fn *msg_callback; void *cbarg; }; static int quic_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio); static int quic_free(OSSL_RECORD_LAYER *r); static int quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, int role, int direction, int level, uint16_t epoch, unsigned char *secret, size_t secretlen, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, const EVP_MD *kdfdigest, BIO *prev, BIO *transport, BIO *next, BIO_ADDR *local, BIO_ADDR *peer, const OSSL_PARAM *settings, const OSSL_PARAM *options, const OSSL_DISPATCH *fns, void *cbarg, void *rlarg, OSSL_RECORD_LAYER **retrl) { OSSL_RECORD_LAYER *rl = OPENSSL_zalloc(sizeof(*rl)); uint32_t enc_level; int qdir; uint32_t suite_id = 0; if (rl == NULL) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } rl->qtls = (QUIC_TLS *)rlarg; rl->level = level; if (!quic_set1_bio(rl, transport)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; } rl->cbarg = cbarg; *retrl = rl; if (fns != NULL) { for (; fns->function_id != 0; fns++) { switch (fns->function_id) { break; case OSSL_FUNC_RLAYER_MSG_CALLBACK: rl->msg_callback = OSSL_FUNC_rlayer_msg_callback(fns); break; default: /* Just ignore anything we don't understand */ break; } } } switch (level) { case OSSL_RECORD_PROTECTION_LEVEL_NONE: return 1; case OSSL_RECORD_PROTECTION_LEVEL_EARLY: enc_level = QUIC_ENC_LEVEL_0RTT; break; case OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE: enc_level = QUIC_ENC_LEVEL_HANDSHAKE; break; case OSSL_RECORD_PROTECTION_LEVEL_APPLICATION: enc_level = QUIC_ENC_LEVEL_1RTT; break; default: QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; } if (direction == OSSL_RECORD_DIRECTION_READ) qdir = 0; else qdir = 1; if (EVP_CIPHER_is_a(ciph, "AES-128-GCM")) { suite_id = QRL_SUITE_AES128GCM; } else if (EVP_CIPHER_is_a(ciph, "AES-256-GCM")) { suite_id = QRL_SUITE_AES256GCM; } else if (EVP_CIPHER_is_a(ciph, "CHACHA20-POLY1305")) { suite_id = QRL_SUITE_CHACHA20POLY1305; } else { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, SSL_R_UNKNOWN_CIPHER_TYPE); goto err; } /* We pass a ref to the md in a successful yield_secret_cb call */ /* TODO(QUIC FUTURE): This cast is horrible. We should try and remove it */ if (!EVP_MD_up_ref((EVP_MD *)kdfdigest)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; } if (!rl->qtls->args.yield_secret_cb(enc_level, qdir, suite_id, (EVP_MD *)kdfdigest, secret, secretlen, rl->qtls->args.yield_secret_cb_arg)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); EVP_MD_free((EVP_MD *)kdfdigest); goto err; } return 1; err: *retrl = NULL; quic_free(rl); return 0; } static int quic_free(OSSL_RECORD_LAYER *rl) { if (rl == NULL) return 1; BIO_free(rl->dummybio); OPENSSL_free(rl); return 1; } static int quic_unprocessed_read_pending(OSSL_RECORD_LAYER *rl) { /* * Read ahead isn't really a thing for QUIC so we never have unprocessed * data pending */ return 0; } static int quic_processed_read_pending(OSSL_RECORD_LAYER *rl) { /* * This is currently only ever used by: * - SSL_has_pending() * - to check whether we have more records that we want to supply to the * upper layers * * We only ever supply 1 record at a time to the upper layers, and * SSL_has_pending() will go via the QUIC method not the TLS method so that * use case doesn't apply here. * Therefore we can ignore this for now and always return 0. We might * eventually want to change this to check in the receive buffers to see if * we have any more data pending. */ return 0; } static size_t quic_get_max_records(OSSL_RECORD_LAYER *rl, uint8_t type, size_t len, size_t maxfrag, size_t *preffrag) { return 1; } static int quic_write_records(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE *template, size_t numtempl) { size_t consumed; unsigned char alert; if (!ossl_assert(numtempl == 1)) { /* How could this be? quic_get_max_records() always returns 1 */ QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } BIO_clear_retry_flags(rl->dummybio); if (rl->msg_callback != NULL) { unsigned char dummyrec[SSL3_RT_HEADER_LENGTH]; /* * For the purposes of the callback we "pretend" to be normal TLS, * and manufacture a dummy record header */ dummyrec[0] = (rl->level == OSSL_RECORD_PROTECTION_LEVEL_NONE) ? template->type : SSL3_RT_APPLICATION_DATA; dummyrec[1] = (unsigned char)((template->version >> 8) & 0xff); dummyrec[2] = (unsigned char)(template->version & 0xff); /* * We assume that buflen is always <= UINT16_MAX. Since this is * generated by libssl itself we actually expect it to never * exceed SSL3_RT_MAX_PLAIN_LENGTH - so it should be a safe * assumption */ dummyrec[3] = (unsigned char)((template->buflen >> 8) & 0xff); dummyrec[4] = (unsigned char)(template->buflen & 0xff); rl->msg_callback(1, TLS1_3_VERSION, SSL3_RT_HEADER, dummyrec, SSL3_RT_HEADER_LENGTH, rl->cbarg); if (rl->level != OSSL_RECORD_PROTECTION_LEVEL_NONE) { rl->msg_callback(1, TLS1_3_VERSION, SSL3_RT_INNER_CONTENT_TYPE, &template->type, 1, rl->cbarg); } } switch (template->type) { case SSL3_RT_ALERT: if (template->buflen != 2) { /* * We assume that libssl always sends both bytes of an alert to * us in one go, and never fragments it. If we ever get more * or less bytes than exactly 2 then this is very unexpected. */ QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_VALUE); return OSSL_RECORD_RETURN_FATAL; } /* * Byte 0 is the alert level (we ignore it) and byte 1 is the alert * description that we are actually interested in. */ alert = template->buf[1]; if (!rl->qtls->args.alert_cb(rl->qtls->args.alert_cb_arg, alert)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } break; case SSL3_RT_HANDSHAKE: /* * We expect this to only fail on some fatal error (e.g. malloc * failure) */ if (!rl->qtls->args.crypto_send_cb(template->buf + rl->written, template->buflen - rl->written, &consumed, rl->qtls->args.crypto_send_cb_arg)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } /* * We might have written less than we wanted to if we have filled the * send stream buffer. */ if (consumed + rl->written != template->buflen) { if (!ossl_assert(consumed + rl->written < template->buflen)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } /* * We've not written everything we wanted to. Take a copy of the * template, remember how much we wrote so far and signal a retry. * The buffer supplied in the template is guaranteed to be the same * on a retry for handshake data */ rl->written += consumed; rl->template = *template; BIO_set_retry_write(rl->dummybio); return OSSL_RECORD_RETURN_RETRY; } rl->written = 0; break; default: /* Anything else is unexpected and an error */ QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } return OSSL_RECORD_RETURN_SUCCESS; } static int quic_retry_write_records(OSSL_RECORD_LAYER *rl) { return quic_write_records(rl, &rl->template, 1); } static int quic_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion, uint8_t *type, const unsigned char **data, size_t *datalen, uint16_t *epoch, unsigned char *seq_num) { if (rl->recread != 0 || rl->recunreleased != 0) return OSSL_RECORD_RETURN_FATAL; BIO_clear_retry_flags(rl->dummybio); if (!rl->qtls->args.crypto_recv_rcd_cb(data, datalen, rl->qtls->args.crypto_recv_rcd_cb_arg)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } if (*datalen == 0) { BIO_set_retry_read(rl->dummybio); return OSSL_RECORD_RETURN_RETRY; } *rechandle = rl; *rversion = TLS1_3_VERSION; *type = SSL3_RT_HANDSHAKE; rl->recread = rl->recunreleased = *datalen; /* epoch/seq_num are not relevant for TLS */ if (rl->msg_callback != NULL) { unsigned char dummyrec[SSL3_RT_HEADER_LENGTH]; /* * For the purposes of the callback we "pretend" to be normal TLS, * and manufacture a dummy record header */ dummyrec[0] = (rl->level == OSSL_RECORD_PROTECTION_LEVEL_NONE) ? SSL3_RT_HANDSHAKE : SSL3_RT_APPLICATION_DATA; dummyrec[1] = (unsigned char)((TLS1_2_VERSION >> 8) & 0xff); dummyrec[2] = (unsigned char)(TLS1_2_VERSION & 0xff); /* * *datalen will always fit into 2 bytes because our original buffer * size is less than that. */ dummyrec[3] = (unsigned char)((*datalen >> 8) & 0xff); dummyrec[4] = (unsigned char)(*datalen & 0xff); rl->msg_callback(0, TLS1_3_VERSION, SSL3_RT_HEADER, dummyrec, SSL3_RT_HEADER_LENGTH, rl->cbarg); rl->msg_callback(0, TLS1_3_VERSION, SSL3_RT_INNER_CONTENT_TYPE, type, 1, rl->cbarg); } return OSSL_RECORD_RETURN_SUCCESS; } static int quic_release_record(OSSL_RECORD_LAYER *rl, void *rechandle, size_t length) { if (!ossl_assert(rl->recread > 0) || !ossl_assert(rl->recunreleased <= rl->recread) || !ossl_assert(rl == rechandle) || !ossl_assert(length <= rl->recunreleased)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } rl->recunreleased -= length; if (rl->recunreleased > 0) return OSSL_RECORD_RETURN_SUCCESS; if (!rl->qtls->args.crypto_release_rcd_cb(rl->recread, rl->qtls->args.crypto_release_rcd_cb_arg)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } rl->recread = 0; return OSSL_RECORD_RETURN_SUCCESS; } static int quic_get_alert_code(OSSL_RECORD_LAYER *rl) { return rl->alert; } static int quic_set_protocol_version(OSSL_RECORD_LAYER *rl, int version) { /* We only support TLSv1.3, so its bad if we negotiate anything else */ if (!ossl_assert(version == TLS1_3_VERSION)) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } return 1; } static void quic_set_plain_alerts(OSSL_RECORD_LAYER *rl, int allow) { /* We don't care */ } static void quic_set_first_handshake(OSSL_RECORD_LAYER *rl, int first) { /* We don't care */ } static void quic_set_max_pipelines(OSSL_RECORD_LAYER *rl, size_t max_pipelines) { /* We don't care */ } static void quic_get_state(OSSL_RECORD_LAYER *rl, const char **shortstr, const char **longstr) { /* * According to the docs, valid read state strings are: "RH"/"read header", * "RB"/"read body", and "unknown"/"unknown". We don't read records in quite * that way, so we report every "normal" state as "read header". In the * event of error then we report "unknown". */ if (rl->qtls->inerror) { if (shortstr != NULL) *shortstr = "unknown"; if (longstr != NULL) *longstr = "unknown"; } else { if (shortstr != NULL) *shortstr = "RH"; if (longstr != NULL) *longstr = "read header"; } } static int quic_set_options(OSSL_RECORD_LAYER *rl, const OSSL_PARAM *options) { /* * We don't support any options yet - but we might do at some point so * this could be useful. */ return 1; } static const COMP_METHOD *quic_get_compression(OSSL_RECORD_LAYER *rl) { /* We only support TLSv1.3 which doesn't have compression */ return NULL; } static void quic_set_max_frag_len(OSSL_RECORD_LAYER *rl, size_t max_frag_len) { /* This really doesn't make any sense for QUIC. Ignore it */ } static int quic_alloc_buffers(OSSL_RECORD_LAYER *rl) { /* * This is a hint only. We don't support it (yet), so just ignore the * request */ return 1; } static int quic_free_buffers(OSSL_RECORD_LAYER *rl) { /* * This is a hint only. We don't support it (yet), so just ignore the * request */ return 1; } static int quic_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio) { if (bio != NULL && !BIO_up_ref(bio)) return 0; BIO_free(rl->dummybio); rl->dummybio = bio; return 1; } /* * Never called functions * * Due to the way we are configured and used we never expect any of the next set * of functions to be called. Therefore we set them to always fail. */ static size_t quic_app_data_pending(OSSL_RECORD_LAYER *rl) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return (size_t)ossl_assert(0); } static size_t quic_get_max_record_overhead(OSSL_RECORD_LAYER *rl) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return (size_t)ossl_assert(0); } static int quic_increment_sequence_ctr(OSSL_RECORD_LAYER *rl) { QUIC_TLS_FATAL(rl, SSL_AD_INTERNAL_ERROR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return ossl_assert(0); } /* End of never called functions */ static const OSSL_RECORD_METHOD quic_tls_record_method = { quic_new_record_layer, quic_free, quic_unprocessed_read_pending, quic_processed_read_pending, quic_app_data_pending, /* Never called */ quic_get_max_records, quic_write_records, quic_retry_write_records, quic_read_record, quic_release_record, quic_get_alert_code, quic_set1_bio, quic_set_protocol_version, quic_set_plain_alerts, quic_set_first_handshake, quic_set_max_pipelines, NULL, /* set_in_init: Optional - we don't need it */ quic_get_state, quic_set_options, quic_get_compression, quic_set_max_frag_len, quic_get_max_record_overhead, /* Never called */ quic_increment_sequence_ctr, /* Never called */ quic_alloc_buffers, quic_free_buffers }; static int add_transport_params_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg) { QUIC_TLS *qtls = add_arg; *out = qtls->local_transport_params; *outlen = qtls->local_transport_params_len; return 1; } static void free_transport_params_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *out, void *add_arg) { } static int parse_transport_params_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg) { QUIC_TLS *qtls = parse_arg; return qtls->args.got_transport_params_cb(in, inlen, qtls->args.got_transport_params_cb_arg); } QUIC_TLS *ossl_quic_tls_new(const QUIC_TLS_ARGS *args) { QUIC_TLS *qtls; if (args->crypto_send_cb == NULL || args->crypto_recv_rcd_cb == NULL || args->crypto_release_rcd_cb == NULL) { ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER); return NULL; } qtls = OPENSSL_zalloc(sizeof(*qtls)); if (qtls == NULL) return NULL; if ((qtls->error_state = OSSL_ERR_STATE_new()) == NULL) { OPENSSL_free(qtls); return NULL; } qtls->args = *args; return qtls; } void ossl_quic_tls_free(QUIC_TLS *qtls) { if (qtls == NULL) return; OSSL_ERR_STATE_free(qtls->error_state); OPENSSL_free(qtls); } static int raise_error(QUIC_TLS *qtls, uint64_t error_code, const char *error_msg, const char *src_file, int src_line, const char *src_func) { /* * When QTLS fails, add a "cover letter" error with information, potentially * with any underlying libssl errors underneath it (but our cover error may * be the only error in some cases). Then capture this into an ERR_STATE so * we can report it later if need be when the QUIC_CHANNEL asks for it. */ ERR_new(); ERR_set_debug(src_file, src_line, src_func); ERR_set_error(ERR_LIB_SSL, SSL_R_QUIC_HANDSHAKE_LAYER_ERROR, "handshake layer error, error code %llu (0x%llx) (\"%s\")", error_code, error_code, error_msg); OSSL_ERR_STATE_save_to_mark(qtls->error_state); /* * We record the error information reported via the QUIC protocol * separately. */ qtls->error_code = error_code; qtls->error_msg = error_msg; qtls->inerror = 1; ERR_pop_to_mark(); return 0; } #define RAISE_ERROR(qtls, error_code, error_msg) \ raise_error((qtls), (error_code), (error_msg), \ OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC) #define RAISE_INTERNAL_ERROR(qtls) \ RAISE_ERROR((qtls), OSSL_QUIC_ERR_INTERNAL_ERROR, "internal error") int ossl_quic_tls_tick(QUIC_TLS *qtls) { int ret, err; const unsigned char *alpn; unsigned int alpnlen; if (qtls->inerror) return 0; /* * SSL_get_error does not truly know what the cause of an SSL_read failure * is and to some extent guesses based on contextual information. In * particular, if there is _any_ ERR on the error stack, SSL_ERROR_SSL or * SSL_ERROR_SYSCALL will be returned no matter what and there is no * possibility of SSL_ERROR_WANT_READ/WRITE being returned, even if that was * the actual cause of the SSL_read() failure. * * This means that ordinarily, the below code might not work right if the * application has any ERR on the error stack. In order to make this code * perform correctly regardless of prior ERR state, we use a variant of * SSL_get_error() which ignores the error stack. However, some ERRs are * raised by SSL_read() and actually indicate that something has gone wrong * during the call to SSL_read(). We therefore adopt a strategy of marking * the ERR stack and seeing if any errors get appended during the call to * SSL_read(). If they are, we assume SSL_read() has raised an error and * that we should use normal SSL_get_error() handling. * * NOTE: Ensure all escape paths from this function call * ERR_clear_to_mark(). The RAISE macros handle this in failure cases. */ ERR_set_mark(); if (!qtls->configured) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(qtls->args.s); SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(sc); BIO *nullbio; /* * No matter how the user has configured us, there are certain * requirements for QUIC-TLS that we enforce */ /* ALPN is a requirement for QUIC and must be set */ if (qtls->args.is_server) { if (sctx->ext.alpn_select_cb == NULL) return RAISE_INTERNAL_ERROR(qtls); } else { if (sc->ext.alpn == NULL || sc->ext.alpn_len == 0) return RAISE_ERROR(qtls, OSSL_QUIC_ERR_CRYPTO_NO_APP_PROTO, "ALPN must be configured when using QUIC"); } if (!SSL_set_min_proto_version(qtls->args.s, TLS1_3_VERSION)) return RAISE_INTERNAL_ERROR(qtls); SSL_clear_options(qtls->args.s, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); ossl_ssl_set_custom_record_layer(sc, &quic_tls_record_method, qtls); if (!ossl_tls_add_custom_ext_intern(NULL, &sc->cert->custext, qtls->args.is_server ? ENDPOINT_SERVER : ENDPOINT_CLIENT, TLSEXT_TYPE_quic_transport_parameters, SSL_EXT_TLS1_3_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, add_transport_params_cb, free_transport_params_cb, qtls, parse_transport_params_cb, qtls)) return RAISE_INTERNAL_ERROR(qtls); nullbio = BIO_new(BIO_s_null()); if (nullbio == NULL) return RAISE_INTERNAL_ERROR(qtls); /* * Our custom record layer doesn't use the BIO - but libssl generally * expects one to be present. */ SSL_set_bio(qtls->args.s, nullbio, nullbio); if (qtls->args.is_server) SSL_set_accept_state(qtls->args.s); else SSL_set_connect_state(qtls->args.s); qtls->configured = 1; } if (qtls->complete) /* * There should never be app data to read, but calling SSL_read() will * ensure any post-handshake messages are processed. */ ret = SSL_read(qtls->args.s, NULL, 0); else ret = SSL_do_handshake(qtls->args.s); if (ret <= 0) { err = ossl_ssl_get_error(qtls->args.s, ret, /*check_err=*/ERR_count_to_mark() > 0); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_CLIENT_HELLO_CB: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_WANT_RETRY_VERIFY: ERR_pop_to_mark(); return 1; default: return RAISE_INTERNAL_ERROR(qtls); } } if (!qtls->complete) { /* Validate that we have ALPN */ SSL_get0_alpn_selected(qtls->args.s, &alpn, &alpnlen); if (alpn == NULL || alpnlen == 0) return RAISE_ERROR(qtls, OSSL_QUIC_ERR_CRYPTO_NO_APP_PROTO, "no application protocol negotiated"); qtls->complete = 1; ERR_pop_to_mark(); return qtls->args.handshake_complete_cb(qtls->args.handshake_complete_cb_arg); } ERR_pop_to_mark(); return 1; } int ossl_quic_tls_set_transport_params(QUIC_TLS *qtls, const unsigned char *transport_params, size_t transport_params_len) { qtls->local_transport_params = transport_params; qtls->local_transport_params_len = transport_params_len; return 1; } int ossl_quic_tls_get_error(QUIC_TLS *qtls, uint64_t *error_code, const char **error_msg, ERR_STATE **error_state) { if (qtls->inerror) { *error_code = qtls->error_code; *error_msg = qtls->error_msg; *error_state = qtls->error_state; } return qtls->inerror; } /* * Returns true if the last handshake record message we processed was a * CertificateRequest */ int ossl_quic_tls_is_cert_request(QUIC_TLS *qtls) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(qtls->args.s); return sc->s3.tmp.message_type == SSL3_MT_CERTIFICATE_REQUEST; } /* * Returns true if the last session associated with the connection has an * invalid max_early_data value for QUIC. */ int ossl_quic_tls_has_bad_max_early_data(QUIC_TLS *qtls) { uint32_t max_early_data = SSL_get0_session(qtls->args.s)->ext.max_early_data; /* * If max_early_data was present we always ensure a non-zero value is * stored in the session for QUIC. Therefore if max_early_data == 0 here * we can be confident that it was not present in the NewSessionTicket */ return max_early_data != 0xffffffff && max_early_data != 0; }