Latest update (add quic)
This commit is contained in:
+285
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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
|
||||
Reference in New Issue
Block a user