286 lines
7.7 KiB
C
286 lines
7.7 KiB
C
/*
|
|
* 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_local.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;
|
|
|
|
/* Check for an incomplete block */
|
|
qd = ssl->quic_input_data_tail;
|
|
if (qd != NULL) {
|
|
l = qd->length - qd->offset;
|
|
if (l != 0) {
|
|
/* we still need to copy `l` bytes into the last data block */
|
|
if (l > len)
|
|
l = len;
|
|
memcpy((char*)(qd+1) + qd->offset, data, l);
|
|
qd->offset += l;
|
|
len -= l;
|
|
data += l;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
n2l3(p, l);
|
|
l += SSL3_HM_HEADER_LENGTH;
|
|
|
|
qd = OPENSSL_zalloc(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;
|
|
/* partial data received? */
|
|
if (l > len)
|
|
l = len;
|
|
qd->offset = l;
|
|
|
|
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 *c2s_secret = NULL;
|
|
uint8_t *s2c_secret = NULL;
|
|
size_t len;
|
|
const EVP_MD *md;
|
|
|
|
if (!SSL_IS_QUIC(ssl))
|
|
return 1;
|
|
|
|
/* secrets from the POV of the client */
|
|
switch (level) {
|
|
case ssl_encryption_early_data:
|
|
c2s_secret = ssl->client_early_traffic_secret;
|
|
break;
|
|
case ssl_encryption_handshake:
|
|
c2s_secret = ssl->client_hand_traffic_secret;
|
|
s2c_secret = ssl->server_hand_traffic_secret;
|
|
break;
|
|
case ssl_encryption_application:
|
|
c2s_secret = ssl->client_app_traffic_secret;
|
|
s2c_secret = ssl->server_app_traffic_secret;
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
|
|
md = ssl_handshake_md(ssl);
|
|
if (md == NULL) {
|
|
/* May not have selected cipher, yet */
|
|
const SSL_CIPHER *c = NULL;
|
|
|
|
if (ssl->session != NULL)
|
|
c = SSL_SESSION_get0_cipher(ssl->session);
|
|
else if (ssl->psksession != NULL)
|
|
c = SSL_SESSION_get0_cipher(ssl->psksession);
|
|
|
|
if (c != NULL)
|
|
md = SSL_CIPHER_get_handshake_digest(c);
|
|
}
|
|
|
|
if ((len = EVP_MD_size(md)) <= 0) {
|
|
SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_SET_ENCRYPTION_SECRETS,
|
|
ERR_R_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
if (ssl->server) {
|
|
if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret,
|
|
s2c_secret, 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, s2c_secret,
|
|
c2s_secret, 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)
|
|
{
|
|
int ret;
|
|
|
|
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);
|
|
ret = ssl->handshake_func(ssl);
|
|
ossl_statem_set_in_init(ssl, 0);
|
|
|
|
if (ret <= 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int SSL_is_quic(SSL* ssl)
|
|
{
|
|
return SSL_IS_QUIC(ssl);
|
|
}
|
|
|
|
#endif
|