Files
openssl-custom/ssl/ssl_quic.c
T
2020-07-12 19:52:18 +09:00

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