mirror of
https://github.com/openssl/openssl.git
synced 2025-01-30 14:01:55 +08:00
QUIC: Dummy Handshake Layer for Prototyping
This disables -Wtype-limits / -Wtautological-constant-out-of-range-compare. Since it generates warnings for valid and reasonable code, IMO this actually encourages people to write worse code. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19703)
This commit is contained in:
parent
964f0deb81
commit
f71ae05a4d
@ -167,7 +167,8 @@ my @gcc_devteam_warn = qw(
|
||||
-Wsign-compare
|
||||
-Wshadow
|
||||
-Wformat
|
||||
-Wtype-limits
|
||||
-Wno-type-limits
|
||||
-Wno-tautological-constant-out-of-range-compare
|
||||
-Wundef
|
||||
-Werror
|
||||
-Wmissing-prototypes
|
||||
|
121
include/internal/quic_dummy_handshake.h
Normal file
121
include/internal/quic_dummy_handshake.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*/
|
||||
|
||||
#ifndef OSSL_QUIC_DUMMY_HANDSHAKE_H
|
||||
# define OSSL_QUIC_DUMMY_HANDSHAKE_H
|
||||
|
||||
# include <openssl/ssl.h>
|
||||
# include "internal/quic_stream.h"
|
||||
|
||||
/*
|
||||
* QUIC Dummy Handshake Module
|
||||
* ===========================
|
||||
*
|
||||
* This implements a fake "handshake layer" for QUIC to be used for testing
|
||||
* purposes until the real handshake layer is ready.
|
||||
*
|
||||
* Each message is of the following form, which reuses the TLS 1.3 framing:
|
||||
*
|
||||
* 1 ui Type
|
||||
* 3 ui Length
|
||||
* ... Data
|
||||
*
|
||||
* The following message types are implemented, which use values from the TLS
|
||||
* HandshakeType registry. Most of them have no body data, except for messages
|
||||
* which transport QUIC Transport Parameters.
|
||||
*
|
||||
* 0x01 Psuedo-ClientHello
|
||||
* (QUIC Transport Parameters)
|
||||
* 0x02 Pseudo-ServerHello
|
||||
* (no data)
|
||||
* 0x08 Pseudo-EncryptedExtensions
|
||||
* (QUIC Transport Parameters)
|
||||
* 0x0B Pseudo-Certificate
|
||||
* (no data)
|
||||
* 0x0F Pseudo-CertificateVerify
|
||||
* (no data)
|
||||
* 0x14 Pseudo-Finished
|
||||
* (no data)
|
||||
*
|
||||
*/
|
||||
typedef struct quic_dhs_st QUIC_DHS;
|
||||
|
||||
typedef struct quic_dhs_args_st {
|
||||
/*
|
||||
* Called to send data on the crypto stream. We use a callback rather than
|
||||
* passing the crypto stream QUIC_SSTREAM directly because this lets the CSM
|
||||
* dynamically select the correct outgoing crypto stream based on the
|
||||
* current EL.
|
||||
*/
|
||||
int (*crypto_send_cb)(const unsigned char *buf, size_t buf_len,
|
||||
size_t *consumed, void *arg);
|
||||
void *crypto_send_cb_arg;
|
||||
int (*crypto_recv_cb)(unsigned char *buf, size_t buf_len,
|
||||
size_t *bytes_read, void *arg);
|
||||
void *crypto_recv_cb_arg;
|
||||
|
||||
/* Called when a traffic secret is available for a given encryption level. */
|
||||
int (*yield_secret_cb)(uint32_t enc_level, int direction /* 0=RX, 1=TX */,
|
||||
uint32_t suite_id, EVP_MD *md,
|
||||
const unsigned char *secret, size_t secret_len,
|
||||
void *arg);
|
||||
void *yield_secret_cb_arg;
|
||||
|
||||
/*
|
||||
* Called when we receive transport parameters from the peer.
|
||||
*
|
||||
* Note: These parameters are not authenticated until the handshake is
|
||||
* marked as completed.
|
||||
*/
|
||||
int (*got_transport_params_cb)(const unsigned char *params,
|
||||
size_t params_len,
|
||||
void *arg);
|
||||
void *got_transport_params_cb_arg;
|
||||
|
||||
/*
|
||||
* Called when the handshake has been completed as far as the handshake
|
||||
* protocol is concerned, meaning that the connection has been
|
||||
* authenticated.
|
||||
*/
|
||||
int (*handshake_complete_cb)(void *arg);
|
||||
void *handshake_complete_cb_arg;
|
||||
|
||||
/*
|
||||
* Called when something has gone wrong with the connection as far as the
|
||||
* handshake layer is concerned, meaning that it should be immediately torn
|
||||
* down. Note that this may happen at any time, including after a connection
|
||||
* has been fully established.
|
||||
*/
|
||||
int (*alert_cb)(void *arg, unsigned char alert_code);
|
||||
void *alert_cb_arg;
|
||||
|
||||
/*
|
||||
* Transport parameters which client should send. Buffer lifetime must
|
||||
* exceed the lifetime of the DHS.
|
||||
*/
|
||||
const unsigned char *transport_params;
|
||||
size_t transport_params_len;
|
||||
} QUIC_DHS_ARGS;
|
||||
|
||||
QUIC_DHS *ossl_quic_dhs_new(const QUIC_DHS_ARGS *args);
|
||||
|
||||
void ossl_quic_dhs_free(QUIC_DHS *dhs);
|
||||
|
||||
/*
|
||||
* Advance the state machine. The DHS considers the receive stream and produces
|
||||
* output on the send stream. Note that after a connection is established this
|
||||
* is unlikely to ever produce any more output, but the handshake layer
|
||||
* nonetheless reserves the right to and it should continue being called
|
||||
* regularly. (When a real handshake layer is used, TLS 1.3 might e.g. produce a
|
||||
* new session ticket; or it might decide to spontaneously produce an alert,
|
||||
* however unlikely.)
|
||||
*/
|
||||
int ossl_quic_dhs_tick(QUIC_DHS *dhs);
|
||||
|
||||
#endif
|
@ -7,3 +7,6 @@ SOURCE[$LIBSSL]=quic_record_rx_wrap.c quic_rx_depack.c
|
||||
SOURCE[$LIBSSL]=quic_fc.c uint_set.c quic_sf_list.c quic_rstream.c quic_sstream.c
|
||||
SOURCE[$LIBSSL]=quic_cfq.c quic_txpim.c quic_fifd.c quic_txp.c
|
||||
SOURCE[$LIBSSL]=quic_stream_map.c
|
||||
SOURCE[$LIBSSL]=quic_sf_list.c quic_rstream.c quic_sstream.c
|
||||
SOURCE[$LIBSSL]=quic_sf_list.c quic_rstream.c quic_sstream.c
|
||||
SOURCE[$LIBSSL]=quic_dummy_handshake.c
|
||||
|
328
ssl/quic/quic_dummy_handshake.c
Normal file
328
ssl/quic/quic_dummy_handshake.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright 2022 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 <openssl/macros.h>
|
||||
#include <openssl/objects.h>
|
||||
#include "internal/quic_dummy_handshake.h"
|
||||
|
||||
#define QUIC_DHS_MSG_TYPE_CH 0x01
|
||||
#define QUIC_DHS_MSG_TYPE_SH 0x02
|
||||
#define QUIC_DHS_MSG_TYPE_EE 0x08
|
||||
#define QUIC_DHS_MSG_TYPE_CERT 0x0B
|
||||
#define QUIC_DHS_MSG_TYPE_CERT_VERIFY 0x0F
|
||||
#define QUIC_DHS_MSG_TYPE_FINISHED 0x14
|
||||
|
||||
#define QUIC_DHS_STATE_INITIAL 0
|
||||
#define QUIC_DHS_STATE_SENT_CH 1
|
||||
#define QUIC_DHS_STATE_RECEIVED_SH 2
|
||||
#define QUIC_DHS_STATE_RECEIVED_EE_HDR 8
|
||||
#define QUIC_DHS_STATE_RECEIVED_EE 3
|
||||
#define QUIC_DHS_STATE_RECEIVED_CERT 4
|
||||
#define QUIC_DHS_STATE_RECEIVED_CERT_VERIFY 5
|
||||
#define QUIC_DHS_STATE_RECEIVED_FINISHED 6
|
||||
#define QUIC_DHS_STATE_SENT_FINISHED 7
|
||||
|
||||
#define QUIC_DHS_STATE_ERROR 0xFF
|
||||
|
||||
struct quic_dhs_st {
|
||||
QUIC_DHS_ARGS args;
|
||||
unsigned char state;
|
||||
unsigned char *server_transport_params;
|
||||
size_t server_transport_params_len;
|
||||
unsigned char rx_hdr[4];
|
||||
size_t rx_hdr_bytes_read;
|
||||
size_t rx_ee_bytes_read;
|
||||
};
|
||||
|
||||
QUIC_DHS *ossl_quic_dhs_new(const QUIC_DHS_ARGS *args)
|
||||
{
|
||||
QUIC_DHS *dhs;
|
||||
|
||||
if (args->crypto_send_cb == NULL
|
||||
|| args->crypto_recv_cb == NULL)
|
||||
return NULL;
|
||||
|
||||
dhs = OPENSSL_zalloc(sizeof(*dhs));
|
||||
if (dhs == NULL)
|
||||
return NULL;
|
||||
|
||||
dhs->args = *args;
|
||||
dhs->state = QUIC_DHS_STATE_INITIAL;
|
||||
return dhs;
|
||||
}
|
||||
|
||||
void ossl_quic_dhs_free(QUIC_DHS *dhs)
|
||||
{
|
||||
if (dhs == NULL)
|
||||
return;
|
||||
|
||||
OPENSSL_free(dhs->server_transport_params);
|
||||
OPENSSL_free(dhs);
|
||||
}
|
||||
|
||||
static int dhs_send(QUIC_DHS *dhs, unsigned char type,
|
||||
const void *buf, size_t buf_len)
|
||||
{
|
||||
size_t consumed = 0;
|
||||
uint32_t len;
|
||||
unsigned char hdr[4];
|
||||
|
||||
len = buf_len;
|
||||
hdr[0] = type;
|
||||
hdr[1] = (len >> 16) & 0xFF;
|
||||
hdr[2] = (len >> 8) & 0xFF;
|
||||
hdr[3] = (len ) & 0xFF;
|
||||
|
||||
if (!dhs->args.crypto_send_cb(hdr, sizeof(hdr), &consumed,
|
||||
dhs->args.crypto_send_cb_arg)
|
||||
|| consumed < sizeof(hdr)
|
||||
|| (buf_len > 0 && (!dhs->args.crypto_send_cb(buf, buf_len, &consumed,
|
||||
dhs->args.crypto_send_cb_arg)
|
||||
|| consumed < buf_len)))
|
||||
/*
|
||||
* We do not handle a full buffer here properly but the DHS produces so
|
||||
* little data this should not matter. By the time we want to fix this
|
||||
* the real handshake layer will be ready.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dhs_recv_sof(QUIC_DHS *dhs, uint32_t *type, size_t *frame_len)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
uint32_t l;
|
||||
|
||||
if (!dhs->args.crypto_recv_cb(dhs->rx_hdr + dhs->rx_hdr_bytes_read,
|
||||
sizeof(dhs->rx_hdr) - dhs->rx_hdr_bytes_read,
|
||||
&bytes_read,
|
||||
dhs->args.crypto_recv_cb_arg))
|
||||
return 0;
|
||||
|
||||
dhs->rx_hdr_bytes_read += bytes_read;
|
||||
if (dhs->rx_hdr_bytes_read < sizeof(dhs->rx_hdr)) {
|
||||
/* Not got entire header yet. */
|
||||
*type = UINT32_MAX;
|
||||
*frame_len = 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
l = (((uint32_t)dhs->rx_hdr[1]) << 16)
|
||||
| (((uint32_t)dhs->rx_hdr[2]) << 8)
|
||||
| (uint32_t)dhs->rx_hdr[3];
|
||||
|
||||
if (l > SIZE_MAX)
|
||||
return 0;
|
||||
|
||||
*type = dhs->rx_hdr[0];
|
||||
*frame_len = (size_t)l;
|
||||
|
||||
dhs->rx_hdr_bytes_read = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dhs_recv_body(QUIC_DHS *dhs, unsigned char *buf, size_t buf_len,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
if (!dhs->args.crypto_recv_cb(buf, buf_len, bytes_read,
|
||||
dhs->args.crypto_recv_cb_arg))
|
||||
return 0;
|
||||
|
||||
if (*bytes_read == 0)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const unsigned char default_handshake_read[32] = {42, 2};
|
||||
static const unsigned char default_handshake_write[32] = {42, 1};
|
||||
static const unsigned char default_1rtt_read[32] = {43, 2};
|
||||
static const unsigned char default_1rtt_write[32] = {43, 1};
|
||||
|
||||
int ossl_quic_dhs_tick(QUIC_DHS *dhs)
|
||||
{
|
||||
int ret;
|
||||
uint32_t type;
|
||||
size_t frame_len, bytes_read = 0;
|
||||
|
||||
for (;;) {
|
||||
switch (dhs->state) {
|
||||
case QUIC_DHS_STATE_INITIAL:
|
||||
/* We need to send a CH */
|
||||
if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_CH,
|
||||
dhs->args.transport_params,
|
||||
dhs->args.transport_params_len))
|
||||
return 0;
|
||||
|
||||
dhs->state = QUIC_DHS_STATE_SENT_CH;
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_SENT_CH:
|
||||
ret = dhs_recv_sof(dhs, &type, &frame_len);
|
||||
if (ret == 1) {
|
||||
if (type == QUIC_DHS_MSG_TYPE_SH && frame_len == 0) {
|
||||
dhs->state = QUIC_DHS_STATE_RECEIVED_SH;
|
||||
|
||||
if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_HANDSHAKE,
|
||||
/*TX=*/0,
|
||||
QRL_SUITE_AES128GCM,
|
||||
NULL,
|
||||
default_handshake_read,
|
||||
sizeof(default_handshake_read),
|
||||
dhs->args.yield_secret_cb_arg))
|
||||
return 0;
|
||||
|
||||
if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_HANDSHAKE,
|
||||
/*TX=*/1,
|
||||
QRL_SUITE_AES128GCM,
|
||||
NULL,
|
||||
default_handshake_write,
|
||||
sizeof(default_handshake_write),
|
||||
dhs->args.yield_secret_cb_arg))
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
return 0; /* error state, unexpected type */
|
||||
}
|
||||
} else if (ret == 2) {
|
||||
return 1; /* no more data yet, not an error */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_RECEIVED_SH:
|
||||
ret = dhs_recv_sof(dhs, &type, &frame_len);
|
||||
if (ret == 1) {
|
||||
if (type == QUIC_DHS_MSG_TYPE_EE) {
|
||||
dhs->state = QUIC_DHS_STATE_RECEIVED_EE_HDR;
|
||||
dhs->rx_ee_bytes_read = 0;
|
||||
dhs->server_transport_params_len = frame_len;
|
||||
dhs->server_transport_params
|
||||
= OPENSSL_malloc(dhs->server_transport_params_len);
|
||||
if (dhs->server_transport_params == NULL)
|
||||
return 0;
|
||||
} else {
|
||||
return 0; /* error state, unexpected type */
|
||||
}
|
||||
} else if (ret == 2) {
|
||||
return 1; /* no more data yet, not an error */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_RECEIVED_EE_HDR:
|
||||
ret = dhs_recv_body(dhs, dhs->server_transport_params + dhs->rx_ee_bytes_read,
|
||||
dhs->server_transport_params_len - dhs->rx_ee_bytes_read,
|
||||
&bytes_read);
|
||||
if (ret == 1) {
|
||||
dhs->rx_ee_bytes_read += bytes_read;
|
||||
if (bytes_read == dhs->server_transport_params_len) {
|
||||
if (!dhs->args.got_transport_params_cb(dhs->server_transport_params,
|
||||
dhs->server_transport_params_len,
|
||||
dhs->args.got_transport_params_cb_arg))
|
||||
return 0;
|
||||
|
||||
dhs->state = QUIC_DHS_STATE_RECEIVED_EE;
|
||||
}
|
||||
} else if (ret == 2) {
|
||||
return 1; /* no more data yet, not an error */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_RECEIVED_EE:
|
||||
/* Expect Cert */
|
||||
ret = dhs_recv_sof(dhs, &type, &frame_len);
|
||||
if (ret == 1) {
|
||||
if (type == QUIC_DHS_MSG_TYPE_CERT && frame_len == 0)
|
||||
dhs->state = QUIC_DHS_STATE_RECEIVED_CERT;
|
||||
else
|
||||
return 0; /* error state, unexpected type */
|
||||
} else if (ret == 2) {
|
||||
return 1; /* no more data yet, not an error */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_RECEIVED_CERT:
|
||||
/* Expect CertVerify */
|
||||
ret = dhs_recv_sof(dhs, &type, &frame_len);
|
||||
if (ret == 1) {
|
||||
if (type == QUIC_DHS_MSG_TYPE_CERT_VERIFY && frame_len == 0)
|
||||
dhs->state = QUIC_DHS_STATE_RECEIVED_CERT_VERIFY;
|
||||
else
|
||||
return 0; /* error state, unexpected type */
|
||||
} else if (ret == 2) {
|
||||
return 1; /* no more data yet, not an error */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_RECEIVED_CERT_VERIFY:
|
||||
/* Expect Finished */
|
||||
ret = dhs_recv_sof(dhs, &type, &frame_len);
|
||||
if (ret == 1) {
|
||||
if (type == QUIC_DHS_MSG_TYPE_FINISHED && frame_len == 0)
|
||||
dhs->state = QUIC_DHS_STATE_RECEIVED_FINISHED;
|
||||
else
|
||||
return 0; /* error state, unexpected type */
|
||||
} else if (ret == 2) {
|
||||
return 1; /* no more data yet, not an error */
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_RECEIVED_FINISHED:
|
||||
/* Send Finished */
|
||||
if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_FINISHED, NULL, 0))
|
||||
return 0;
|
||||
|
||||
dhs->state = QUIC_DHS_STATE_SENT_FINISHED;
|
||||
|
||||
if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_1RTT,
|
||||
/*TX=*/0,
|
||||
QRL_SUITE_AES128GCM,
|
||||
NULL,
|
||||
default_1rtt_read,
|
||||
sizeof(default_1rtt_read),
|
||||
dhs->args.yield_secret_cb_arg))
|
||||
return 0;
|
||||
|
||||
if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_1RTT,
|
||||
/*TX=*/1,
|
||||
QRL_SUITE_AES128GCM,
|
||||
NULL,
|
||||
default_1rtt_write,
|
||||
sizeof(default_1rtt_write),
|
||||
dhs->args.yield_secret_cb_arg))
|
||||
return 0;
|
||||
|
||||
if (!dhs->args.handshake_complete_cb(dhs->args.handshake_complete_cb_arg))
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case QUIC_DHS_STATE_SENT_FINISHED:
|
||||
/* Nothing to do, handshake complete. */
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0; /* error state */
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user