mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-08-06 11:53:39 +08:00
1011 lines
34 KiB
C
1011 lines
34 KiB
C
/*
|
|
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
|
* not use this file except in compliance with the License.
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <gmssl/quic.h>
|
|
#include <gmssl/tls.h>
|
|
#include <gmssl/socket.h>
|
|
#include <gmssl/error.h>
|
|
|
|
int tls13_generate_application_secrets(TLS_CONNECT *conn);
|
|
int tls13_generate_client_application_keys(TLS_CONNECT *conn);
|
|
int tls13_generate_server_application_keys(TLS_CONNECT *conn);
|
|
int tls13_record_set_handshake_encrypted_extensions(uint8_t *record, size_t *recordlen, const uint8_t *exts, size_t extslen);
|
|
|
|
static const char *options = "[-port num] -cert pem -key pem [-pass str] [-cipher_suite str] [-supported_group str] [-sig_alg str] [-verbose]";
|
|
|
|
static const char *help =
|
|
"Options\n"
|
|
"\n"
|
|
" -port num Listening UDP port number, default 443\n"
|
|
" -cert pem Server's certificate chain in PEM format\n"
|
|
" -key pem Server's encrypted private key in PEM format\n"
|
|
" -pass str Password to decrypt private key\n"
|
|
" -cipher_suite str TLS 1.3 cipher suite, default TLS_AES_128_GCM_SHA256 and TLS_AES_128_CCM_SHA256\n"
|
|
" -supported_group str Supported elliptic curve, default prime256v1\n"
|
|
" -sig_alg str Supported signature algorithm, default ecdsa_secp256r1_sha256\n"
|
|
" -verbose Print QUIC packet, frame and TLS handshake messages\n"
|
|
"\n"
|
|
#include "quic_help.h"
|
|
;
|
|
|
|
static int quic_tls_record_from_handshake(const uint8_t *handshake, size_t handshake_len, uint8_t *record, size_t *record_len)
|
|
{
|
|
if (!handshake || !record || !record_len || handshake_len > TLS_MAX_PLAINTEXT_SIZE) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
record[0] = TLS_record_handshake;
|
|
record[1] = 0x03;
|
|
record[2] = 0x03;
|
|
record[3] = (uint8_t)(handshake_len >> 8);
|
|
record[4] = (uint8_t)handshake_len;
|
|
memcpy(record + TLS_RECORD_HEADER_SIZE, handshake, handshake_len);
|
|
*record_len = TLS_RECORD_HEADER_SIZE + handshake_len;
|
|
return 1;
|
|
}
|
|
|
|
static int quic_long_packet_connection_ids_get(const uint8_t *packet, size_t packet_len,
|
|
const uint8_t **dcid, size_t *dcid_len, const uint8_t **scid, size_t *scid_len)
|
|
{
|
|
const uint8_t *p;
|
|
size_t len;
|
|
uint8_t n;
|
|
|
|
if (!packet || packet_len < 7 || !(packet[0] & 0x80) || !dcid || !dcid_len || !scid || !scid_len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
p = packet + 5;
|
|
len = packet_len - 5;
|
|
n = *p++;
|
|
len--;
|
|
if (n > len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
*dcid = p;
|
|
*dcid_len = n;
|
|
p += n;
|
|
len -= n;
|
|
if (!len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
n = *p++;
|
|
len--;
|
|
if (n > len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
*scid = p;
|
|
*scid_len = n;
|
|
return 1;
|
|
}
|
|
|
|
static int quic_ack_frame_to_bytes(uint64_t packet_number, uint8_t **out, size_t *outlen)
|
|
{
|
|
if (quic_varint_to_bytes(QUIC_frame_ack, out, outlen) != 1
|
|
|| quic_varint_to_bytes(packet_number, out, outlen) != 1
|
|
|| quic_varint_to_bytes(0, out, outlen) != 1
|
|
|| quic_varint_to_bytes(0, out, outlen) != 1
|
|
|| quic_varint_to_bytes(0, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_crypto_frame_to_bytes(uint64_t offset, const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen)
|
|
{
|
|
if ((!data && datalen)
|
|
|| quic_varint_to_bytes(QUIC_frame_crypto, out, outlen) != 1
|
|
|| quic_varint_to_bytes(offset, out, outlen) != 1
|
|
|| quic_varint_to_bytes(datalen, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (out && *out) {
|
|
memcpy(*out, data, datalen);
|
|
*out += datalen;
|
|
}
|
|
*outlen += datalen;
|
|
return 1;
|
|
}
|
|
|
|
static int quic_stream_frame_to_bytes(uint64_t stream_id, uint64_t offset, int fin, const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen)
|
|
{
|
|
uint64_t type = QUIC_frame_stream_base | 0x02 | (offset ? 0x04 : 0) | (fin ? 0x01 : 0);
|
|
|
|
if ((!data && datalen)
|
|
|| quic_varint_to_bytes(type, out, outlen) != 1
|
|
|| quic_varint_to_bytes(stream_id, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (offset && quic_varint_to_bytes(offset, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (quic_varint_to_bytes(datalen, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (out && *out) {
|
|
memcpy(*out, data, datalen);
|
|
*out += datalen;
|
|
}
|
|
*outlen += datalen;
|
|
return 1;
|
|
}
|
|
|
|
static int quic_frames_crypto_collect(const uint8_t *frames, size_t frames_len,
|
|
uint8_t *crypto, size_t *crypto_len, size_t crypto_max, uint64_t *largest_ack)
|
|
{
|
|
const uint8_t *p = frames;
|
|
size_t len = frames_len;
|
|
|
|
if (!frames || !crypto || !crypto_len || !largest_ack) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
while (len) {
|
|
uint64_t type;
|
|
if (quic_varint_from_bytes(&type, &p, &len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (type == QUIC_frame_padding) {
|
|
while (len && *p == 0) {
|
|
p++;
|
|
len--;
|
|
}
|
|
} else if (type == QUIC_frame_ping) {
|
|
continue;
|
|
} else if (type == QUIC_frame_ack || type == QUIC_frame_ack_ecn) {
|
|
uint64_t ack_delay, ack_range_count, first_ack_range, i;
|
|
if (quic_varint_from_bytes(largest_ack, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&ack_delay, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&ack_range_count, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&first_ack_range, &p, &len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
for (i = 0; i < ack_range_count; i++) {
|
|
uint64_t gap, ack_range;
|
|
if (quic_varint_from_bytes(&gap, &p, &len) != 1 || quic_varint_from_bytes(&ack_range, &p, &len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
}
|
|
if (type == QUIC_frame_ack_ecn) {
|
|
uint64_t ect0, ect1, ce;
|
|
if (quic_varint_from_bytes(&ect0, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&ect1, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&ce, &p, &len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
}
|
|
} else if (type == QUIC_frame_crypto) {
|
|
uint64_t off, data_len;
|
|
if (quic_varint_from_bytes(&off, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&data_len, &p, &len) != 1
|
|
|| data_len > len || off + data_len > crypto_max) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
memcpy(crypto + off, p, (size_t)data_len);
|
|
if (*crypto_len < off + data_len) {
|
|
*crypto_len = (size_t)(off + data_len);
|
|
}
|
|
p += data_len;
|
|
len -= data_len;
|
|
} else {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_tls_handshake_is_complete(const uint8_t *handshake, size_t handshake_len)
|
|
{
|
|
size_t len;
|
|
|
|
if (!handshake || handshake_len < TLS_HANDSHAKE_HEADER_SIZE) {
|
|
return 0;
|
|
}
|
|
len = ((size_t)handshake[1] << 16) | ((size_t)handshake[2] << 8) | handshake[3];
|
|
return handshake_len >= TLS_HANDSHAKE_HEADER_SIZE + len;
|
|
}
|
|
|
|
static int quic_server_client_hello_process(TLS_CONNECT *conn, const uint8_t *client_hello, size_t client_hello_len)
|
|
{
|
|
uint8_t record[TLS_MAX_RECORD_SIZE];
|
|
size_t record_len;
|
|
int legacy_version;
|
|
const uint8_t *random;
|
|
const uint8_t *legacy_session_id;
|
|
size_t legacy_session_id_len;
|
|
const uint8_t *cipher_suites;
|
|
size_t cipher_suites_len;
|
|
const uint8_t *exts;
|
|
size_t extslen;
|
|
const uint8_t *supported_versions = NULL;
|
|
size_t supported_versions_len = 0;
|
|
const uint8_t *supported_groups = NULL;
|
|
size_t supported_groups_len = 0;
|
|
const uint8_t *signature_algorithms = NULL;
|
|
size_t signature_algorithms_len = 0;
|
|
const uint8_t *key_share = NULL;
|
|
size_t key_share_len = 0;
|
|
const uint8_t *server_name = NULL;
|
|
size_t server_name_len = 0;
|
|
const uint8_t *alpn = NULL;
|
|
size_t alpn_len = 0;
|
|
int common_versions[4];
|
|
size_t common_versions_cnt = 0;
|
|
int common_groups[4];
|
|
size_t common_groups_cnt = 0;
|
|
int common_sig_algs[8];
|
|
size_t common_sig_algs_cnt = 0;
|
|
const uint8_t *host_name = NULL;
|
|
size_t host_name_len = 0;
|
|
int group = 0;
|
|
const uint8_t *key_exchange = NULL;
|
|
size_t key_exchange_len = 0;
|
|
int ret;
|
|
|
|
if (!conn || !client_hello || !client_hello_len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (quic_tls_record_from_handshake(client_hello, client_hello_len, record, &record_len) != 1
|
|
|| tls_record_get_handshake_client_hello(record, &legacy_version, &random, &legacy_session_id,
|
|
&legacy_session_id_len, &cipher_suites, &cipher_suites_len, &exts, &extslen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (legacy_version != TLS_protocol_tls12) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
memcpy(conn->client_random, random, 32);
|
|
if (legacy_session_id_len > sizeof(conn->session_id)) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
memcpy(conn->session_id, legacy_session_id, legacy_session_id_len);
|
|
conn->session_id_len = legacy_session_id_len;
|
|
|
|
while (extslen) {
|
|
int ext_type;
|
|
const uint8_t *ext_data;
|
|
size_t ext_datalen;
|
|
|
|
if (tls_ext_from_bytes(&ext_type, &ext_data, &ext_datalen, &exts, &extslen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
switch (ext_type) {
|
|
case TLS_extension_supported_versions:
|
|
supported_versions = ext_data;
|
|
supported_versions_len = ext_datalen;
|
|
break;
|
|
case TLS_extension_supported_groups:
|
|
supported_groups = ext_data;
|
|
supported_groups_len = ext_datalen;
|
|
break;
|
|
case TLS_extension_signature_algorithms:
|
|
signature_algorithms = ext_data;
|
|
signature_algorithms_len = ext_datalen;
|
|
break;
|
|
case TLS_extension_key_share:
|
|
key_share = ext_data;
|
|
key_share_len = ext_datalen;
|
|
break;
|
|
case TLS_extension_server_name:
|
|
server_name = ext_data;
|
|
server_name_len = ext_datalen;
|
|
break;
|
|
case TLS_extension_application_layer_protocol_negotiation:
|
|
alpn = ext_data;
|
|
alpn_len = ext_datalen;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (!supported_versions || !supported_groups || !signature_algorithms || !key_share || !alpn) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if ((ret = tls13_process_client_supported_versions(supported_versions, supported_versions_len,
|
|
conn->ctx->supported_versions, conn->ctx->supported_versions_cnt,
|
|
common_versions, &common_versions_cnt, sizeof(common_versions)/sizeof(common_versions[0]))) != 1
|
|
|| common_versions[0] != TLS_protocol_tls13) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
conn->protocol = TLS_protocol_tls13;
|
|
if ((ret = tls_process_supported_groups(supported_groups, supported_groups_len,
|
|
conn->ctx->supported_groups, conn->ctx->supported_groups_cnt,
|
|
common_groups, &common_groups_cnt, sizeof(common_groups)/sizeof(common_groups[0]))) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if ((ret = tls_process_signature_algorithms(signature_algorithms, signature_algorithms_len,
|
|
conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt,
|
|
common_sig_algs, &common_sig_algs_cnt, sizeof(common_sig_algs)/sizeof(common_sig_algs[0]))) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (server_name
|
|
&& tls_server_name_from_bytes(&host_name, &host_name_len, server_name, server_name_len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if ((ret = tls_application_layer_protocol_negotiation_select(alpn, alpn_len,
|
|
conn->ctx->alpn_protocols, conn->ctx->alpn_protocols_cnt, &conn->alpn_selected)) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if ((ret = tls13_cert_chains_select(conn->ctx->cert_chains, conn->ctx->cert_chains_len,
|
|
common_sig_algs, common_sig_algs_cnt, NULL, 0, NULL, 0, NULL, 0, host_name, host_name_len,
|
|
&conn->cert_chain, &conn->cert_chain_len, &conn->cert_chain_idx, &conn->sig_alg)) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (tls_cipher_suites_select(cipher_suites, cipher_suites_len,
|
|
conn->ctx->cipher_suites, conn->ctx->cipher_suites_cnt, &conn->cipher_suite) != 1
|
|
|| tls_cipher_suite_get(conn->cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (tls13_process_key_share_client_hello(key_share, key_share_len, common_groups, common_groups_cnt,
|
|
&group, &key_exchange, &key_exchange_len) != 1 || key_exchange_len != 65) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
conn->key_exchange_group = group;
|
|
memcpy(conn->peer_key_exchange, key_exchange, key_exchange_len);
|
|
conn->peer_key_exchange_len = key_exchange_len;
|
|
conn->key_exchange_modes = TLS_KE_CERT_DHE;
|
|
if (digest_init(&conn->dgst_ctx, conn->digest) != 1
|
|
|| digest_update(&conn->dgst_ctx, client_hello, client_hello_len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_record_handshake_append(TLS_CONNECT *conn, const uint8_t *record, size_t record_len, uint8_t **out, size_t *outlen)
|
|
{
|
|
const uint8_t *handshake;
|
|
size_t handshake_len;
|
|
|
|
if (!conn || !record || record_len < TLS_RECORD_HEADER_SIZE || !outlen
|
|
|| tls_record_type(record) != TLS_record_handshake || tls_record_length(record) != record_len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
handshake = record + TLS_RECORD_HEADER_SIZE;
|
|
handshake_len = record_len - TLS_RECORD_HEADER_SIZE;
|
|
if (out && *out) {
|
|
memcpy(*out, handshake, handshake_len);
|
|
*out += handshake_len;
|
|
}
|
|
*outlen += handshake_len;
|
|
if (digest_update(&conn->dgst_ctx, handshake, handshake_len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void quic_tls_record_header_init(uint8_t *record)
|
|
{
|
|
record[0] = TLS_record_handshake;
|
|
record[1] = 0x03;
|
|
record[2] = 0x03;
|
|
}
|
|
|
|
static int quic_server_encrypted_extensions_to_bytes(TLS_CONNECT *conn, const QUIC_TRANSPORT_PARAMS *params, uint8_t **out, size_t *outlen)
|
|
{
|
|
uint8_t exts[512];
|
|
uint8_t *pexts = exts;
|
|
size_t extslen = 0;
|
|
uint8_t transport_params[QUIC_TRANSPORT_PARAM_MAX_SIZE];
|
|
uint8_t *ptransport_params = transport_params;
|
|
size_t transport_params_len = 0;
|
|
uint8_t record[TLS_MAX_RECORD_SIZE];
|
|
size_t record_len = 0;
|
|
|
|
if (!conn || !params || !outlen) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
quic_tls_record_header_init(record);
|
|
if (tls_application_layer_protocol_negotiation_selected_ext_to_bytes(conn->alpn_selected, &pexts, &extslen) != 1
|
|
|| quic_transport_params_to_bytes(params, &ptransport_params, &transport_params_len) != 1
|
|
|| tls_ext_to_bytes(TLS_extension_quic_transport_parameters, transport_params, transport_params_len, &pexts, &extslen) != 1
|
|
|| tls13_record_set_handshake_encrypted_extensions(record, &record_len, exts, extslen) != 1
|
|
|| quic_record_handshake_append(conn, record, record_len, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_server_certificate_to_bytes(TLS_CONNECT *conn, uint8_t **out, size_t *outlen)
|
|
{
|
|
uint8_t record[TLS_MAX_RECORD_SIZE];
|
|
size_t record_len = 0;
|
|
|
|
if (!conn || !outlen) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
quic_tls_record_header_init(record);
|
|
if (tls13_record_set_handshake_certificate(record, &record_len, NULL, 0,
|
|
conn->cert_chain, conn->cert_chain_len, NULL, 0, NULL, 0) != 1
|
|
|| quic_record_handshake_append(conn, record, record_len, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_server_certificate_verify_to_bytes(TLS_CONNECT *conn, uint8_t **out, size_t *outlen)
|
|
{
|
|
X509_KEY *sign_key;
|
|
uint8_t sig[SM2_MAX_SIGNATURE_SIZE];
|
|
size_t siglen;
|
|
uint8_t record[TLS_MAX_RECORD_SIZE];
|
|
size_t record_len = 0;
|
|
|
|
if (!conn || !outlen || !conn->cert_chain_idx) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
quic_tls_record_header_init(record);
|
|
sign_key = &conn->ctx->x509_keys[conn->cert_chain_idx - 1];
|
|
if (tls13_sign_certificate_verify(TLS_server_mode, conn->sig_alg, sign_key, &conn->dgst_ctx, sig, &siglen) != 1
|
|
|| tls13_record_set_handshake_certificate_verify(record, &record_len, conn->sig_alg, sig, siglen) != 1
|
|
|| quic_record_handshake_append(conn, record, record_len, out, outlen) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_server_finished_to_bytes(TLS_CONNECT *conn, uint8_t **out, size_t *outlen)
|
|
{
|
|
uint8_t verify_data[64];
|
|
size_t verify_data_len;
|
|
uint8_t record[TLS_MAX_RECORD_SIZE];
|
|
size_t record_len = 0;
|
|
const uint8_t *handshake;
|
|
size_t handshake_len;
|
|
|
|
if (!conn || !outlen) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
quic_tls_record_header_init(record);
|
|
if (tls13_compute_verify_data(conn->server_handshake_traffic_secret, &conn->dgst_ctx, verify_data, &verify_data_len) != 1
|
|
|| tls13_record_set_handshake_finished(record, &record_len, verify_data, verify_data_len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
handshake = record + TLS_RECORD_HEADER_SIZE;
|
|
handshake_len = record_len - TLS_RECORD_HEADER_SIZE;
|
|
if (out && *out) {
|
|
memcpy(*out, handshake, handshake_len);
|
|
*out += handshake_len;
|
|
}
|
|
*outlen += handshake_len;
|
|
if (digest_update(&conn->dgst_ctx, handshake, handshake_len) != 1
|
|
|| tls13_generate_application_secrets(conn) != 1
|
|
|| tls13_generate_server_application_keys(conn) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_server_client_finished_process(TLS_CONNECT *conn, const uint8_t *handshake, size_t handshake_len)
|
|
{
|
|
uint8_t record[TLS_MAX_RECORD_SIZE];
|
|
size_t record_len;
|
|
const uint8_t *client_verify_data;
|
|
size_t client_verify_data_len;
|
|
uint8_t verify_data[64];
|
|
size_t verify_data_len;
|
|
|
|
if (!conn || !handshake || !handshake_len) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
if (quic_tls_record_from_handshake(handshake, handshake_len, record, &record_len) != 1
|
|
|| tls13_compute_verify_data(conn->client_handshake_traffic_secret, &conn->dgst_ctx, verify_data, &verify_data_len) != 1
|
|
|| tls13_record_get_handshake_finished(record, &client_verify_data, &client_verify_data_len) != 1
|
|
|| client_verify_data_len != verify_data_len
|
|
|| memcmp(client_verify_data, verify_data, verify_data_len) != 0
|
|
|| digest_update(&conn->dgst_ctx, handshake, handshake_len) != 1
|
|
|| tls13_generate_client_application_keys(conn) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_http3_response_to_frames(uint64_t request_stream_id, const uint8_t *body, size_t body_len, uint64_t ack_pn, uint8_t *frames, size_t *frames_len)
|
|
{
|
|
uint8_t control_stream[] = { 0x00, 0x04, 0x00 };
|
|
uint8_t qpack_encoder_stream[] = { 0x02 };
|
|
uint8_t qpack_decoder_stream[] = { 0x03 };
|
|
uint8_t headers[] = { 0x01, 0x03, 0x00, 0x00, 0xd9 };
|
|
uint8_t data[512];
|
|
uint8_t *p = frames;
|
|
uint8_t *q = data;
|
|
size_t data_len = 0;
|
|
|
|
if (!body || !frames || !frames_len || body_len > 255) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
*frames_len = 0;
|
|
if (quic_varint_to_bytes(0x00, &q, &data_len) != 1
|
|
|| quic_varint_to_bytes(body_len, &q, &data_len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
memcpy(q, body, body_len);
|
|
data_len += body_len;
|
|
if (quic_ack_frame_to_bytes(ack_pn, &p, frames_len) != 1
|
|
|| quic_varint_to_bytes(QUIC_frame_handshake_done, &p, frames_len) != 1
|
|
|| quic_stream_frame_to_bytes(3, 0, 0, control_stream, sizeof(control_stream), &p, frames_len) != 1
|
|
|| quic_stream_frame_to_bytes(7, 0, 0, qpack_encoder_stream, sizeof(qpack_encoder_stream), &p, frames_len) != 1
|
|
|| quic_stream_frame_to_bytes(11, 0, 0, qpack_decoder_stream, sizeof(qpack_decoder_stream), &p, frames_len) != 1
|
|
|| quic_stream_frame_to_bytes(request_stream_id, 0, 0, headers, sizeof(headers), &p, frames_len) != 1
|
|
|| quic_stream_frame_to_bytes(request_stream_id, sizeof(headers), 1, data, data_len, &p, frames_len) != 1) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int quic_application_request_stream_id(const uint8_t *frames, size_t frames_len, uint64_t *packet_number, uint64_t *stream_id)
|
|
{
|
|
const uint8_t *p = frames;
|
|
size_t len = frames_len;
|
|
|
|
if (!frames || !stream_id) {
|
|
error_print();
|
|
return -1;
|
|
}
|
|
*stream_id = 0;
|
|
while (len) {
|
|
uint64_t type;
|
|
if (quic_varint_from_bytes(&type, &p, &len) != 1) return -1;
|
|
if (type == QUIC_frame_padding) {
|
|
while (len && *p == 0) { p++; len--; }
|
|
} else if (type == QUIC_frame_ack || type == QUIC_frame_ack_ecn) {
|
|
uint64_t val, range_count, i;
|
|
if (quic_varint_from_bytes(&val, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&val, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&range_count, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&val, &p, &len) != 1) return -1;
|
|
for (i = 0; i < range_count; i++) {
|
|
if (quic_varint_from_bytes(&val, &p, &len) != 1 || quic_varint_from_bytes(&val, &p, &len) != 1) return -1;
|
|
}
|
|
if (type == QUIC_frame_ack_ecn) {
|
|
if (quic_varint_from_bytes(&val, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&val, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&val, &p, &len) != 1) return -1;
|
|
}
|
|
} else if ((type & 0xf8) == QUIC_frame_stream_base) {
|
|
uint64_t off = 0, data_len;
|
|
if (quic_varint_from_bytes(stream_id, &p, &len) != 1) return -1;
|
|
if (type & 0x04) {
|
|
if (quic_varint_from_bytes(&off, &p, &len) != 1) return -1;
|
|
}
|
|
if (type & 0x02) {
|
|
if (quic_varint_from_bytes(&data_len, &p, &len) != 1 || data_len > len) return -1;
|
|
} else {
|
|
data_len = len;
|
|
}
|
|
(void)off;
|
|
p += data_len;
|
|
len -= data_len;
|
|
if ((*stream_id & 0x03) == 0) {
|
|
if (packet_number) *packet_number = 0;
|
|
return 1;
|
|
}
|
|
} else if (type == QUIC_frame_new_connection_id) {
|
|
uint64_t seq, retire, cid_len;
|
|
if (quic_varint_from_bytes(&seq, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&retire, &p, &len) != 1
|
|
|| quic_varint_from_bytes(&cid_len, &p, &len) != 1
|
|
|| cid_len > 20 || cid_len + 16 > len) return -1;
|
|
p += cid_len + 16;
|
|
len -= cid_len + 16;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int quic_server_main(int argc, char **argv)
|
|
{
|
|
char *prog = argv[0];
|
|
int ret = 1;
|
|
int port = 443;
|
|
char *certfile = NULL;
|
|
char *keyfile = NULL;
|
|
char *pass = NULL;
|
|
int verbose = 0;
|
|
TLS_CTX ctx;
|
|
TLS_CONNECT conn;
|
|
int cipher_suites[TLS_MAX_CIPHER_SUITES] = { TLS_cipher_aes_128_gcm_sha256, TLS_cipher_aes_128_ccm_sha256 };
|
|
size_t cipher_suites_cnt = 2;
|
|
int supported_group = TLS_curve_secp256r1;
|
|
int sig_alg = TLS_sig_ecdsa_secp256r1_sha256;
|
|
char *alpn = "h3";
|
|
tls_socket_t sock = tls_socket_invalid();
|
|
struct sockaddr_in server_addr;
|
|
struct sockaddr_in client_addr;
|
|
tls_socklen_t client_addr_len;
|
|
uint8_t buf[4096];
|
|
uint8_t sendbuf[4096];
|
|
uint8_t initial_crypto[TLS_MAX_RECORD_SIZE];
|
|
size_t initial_crypto_len = 0;
|
|
uint8_t handshake_crypto[TLS_MAX_RECORD_SIZE];
|
|
size_t handshake_crypto_len = 0;
|
|
uint8_t server_initial_crypto[TLS_MAX_RECORD_SIZE];
|
|
uint8_t server_handshake_crypto[TLS_MAX_RECORD_SIZE];
|
|
uint8_t frames[TLS_MAX_RECORD_SIZE];
|
|
uint8_t packet[1500];
|
|
uint8_t server_dcid[20];
|
|
size_t server_dcid_len = 0;
|
|
uint8_t server_scid[20] = {
|
|
0x51, 0x72, 0x9a, 0x41, 0x3e, 0x55, 0x12, 0x3f,
|
|
0x7b, 0x20, 0x65, 0x94, 0xac, 0x37, 0xd1, 0xe8,
|
|
};
|
|
size_t server_scid_len = 16;
|
|
size_t server_initial_crypto_len = 0;
|
|
size_t server_handshake_crypto_len = 0;
|
|
size_t frames_len = 0;
|
|
size_t packet_len = 0;
|
|
uint8_t *p;
|
|
QUIC_INITIAL_SECRETS initial_secrets;
|
|
QUIC_INITIAL_KEYS initial_client_keys0;
|
|
QUIC_INITIAL_KEYS initial_server_keys0;
|
|
QUIC_PACKET_KEYS initial_client_keys;
|
|
QUIC_PACKET_KEYS initial_server_keys;
|
|
QUIC_PACKET_KEYS client_handshake_keys;
|
|
QUIC_PACKET_KEYS server_handshake_keys;
|
|
QUIC_PACKET_KEYS client_application_keys;
|
|
QUIC_PACKET_KEYS server_application_keys;
|
|
QUIC_DECRYPTED_PACKET decrypted;
|
|
QUIC_TRANSPORT_PARAMS params;
|
|
uint64_t largest_ack = 0;
|
|
uint64_t request_stream_id = 0;
|
|
tls_ret_t n;
|
|
|
|
argc--;
|
|
argv++;
|
|
if (argc < 1) {
|
|
fprintf(stderr, "usage: %s %s\n", prog, options);
|
|
return 1;
|
|
}
|
|
while (argc > 0) {
|
|
if (!strcmp(*argv, "-help")) {
|
|
printf("usage: %s %s\n", prog, options);
|
|
printf("%s\n", help);
|
|
return 0;
|
|
} else if (!strcmp(*argv, "-port")) {
|
|
if (--argc < 1) goto bad;
|
|
port = atoi(*(++argv));
|
|
} else if (!strcmp(*argv, "-cert")) {
|
|
if (--argc < 1) goto bad;
|
|
certfile = *(++argv);
|
|
} else if (!strcmp(*argv, "-key")) {
|
|
if (--argc < 1) goto bad;
|
|
keyfile = *(++argv);
|
|
} else if (!strcmp(*argv, "-pass")) {
|
|
if (--argc < 1) goto bad;
|
|
pass = *(++argv);
|
|
} else if (!strcmp(*argv, "-cipher_suite")) {
|
|
int cipher_suite;
|
|
if (--argc < 1) goto bad;
|
|
if ((cipher_suite = tls_cipher_suite_from_name(*(++argv))) == 0) {
|
|
fprintf(stderr, "%s: invalid cipher suite '%s'\n", prog, *argv);
|
|
return 1;
|
|
}
|
|
if (cipher_suites_cnt == 2 && cipher_suites[0] == TLS_cipher_aes_128_gcm_sha256 && cipher_suites[1] == TLS_cipher_aes_128_ccm_sha256) {
|
|
cipher_suites_cnt = 0;
|
|
}
|
|
if (cipher_suites_cnt >= sizeof(cipher_suites)/sizeof(cipher_suites[0])) {
|
|
fprintf(stderr, "%s: too many -cipher_suite options\n", prog);
|
|
return 1;
|
|
}
|
|
cipher_suites[cipher_suites_cnt++] = cipher_suite;
|
|
} else if (!strcmp(*argv, "-supported_group")) {
|
|
if (--argc < 1) goto bad;
|
|
if ((supported_group = tls_named_curve_from_name(*(++argv))) == 0) {
|
|
fprintf(stderr, "%s: invalid supported group '%s'\n", prog, *argv);
|
|
return 1;
|
|
}
|
|
} else if (!strcmp(*argv, "-sig_alg")) {
|
|
if (--argc < 1) goto bad;
|
|
if ((sig_alg = tls_signature_scheme_from_name(*(++argv))) == 0) {
|
|
fprintf(stderr, "%s: invalid signature algorithm '%s'\n", prog, *argv);
|
|
return 1;
|
|
}
|
|
} else if (!strcmp(*argv, "-verbose")) {
|
|
verbose = 1;
|
|
} else {
|
|
fprintf(stderr, "%s: invalid option '%s'\n", prog, *argv);
|
|
return 1;
|
|
bad:
|
|
fprintf(stderr, "%s: option '%s' argument required\n", prog, *argv);
|
|
return 1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if (!certfile || !keyfile) {
|
|
fprintf(stderr, "%s: -cert and -key required\n", prog);
|
|
return 1;
|
|
}
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
memset(&conn, 0, sizeof(conn));
|
|
if (tls_socket_lib_init() != 1
|
|
|| tls_ctx_init(&ctx, TLS_protocol_tls13, TLS_server_mode) != 1
|
|
|| tls_ctx_set_cipher_suites(&ctx, cipher_suites, cipher_suites_cnt) != 1
|
|
|| tls_ctx_set_supported_groups(&ctx, &supported_group, 1) != 1
|
|
|| tls_ctx_set_signature_algorithms(&ctx, &sig_alg, 1) != 1
|
|
|| tls_ctx_set_application_layer_protocol_negotiation(&ctx, &alpn, 1) != 1
|
|
|| tls_ctx_add_certificate_chain_and_key(&ctx, certfile, keyfile, pass ? pass : "") != 1
|
|
|| tls_init(&conn, &ctx) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
conn.verbose = verbose ? TLS_verbose : 0;
|
|
|
|
if (tls_socket_create(&sock, AF_INET, SOCK_DGRAM, 0) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
memset(&server_addr, 0, sizeof(server_addr));
|
|
server_addr.sin_family = AF_INET;
|
|
server_addr.sin_addr.s_addr = INADDR_ANY;
|
|
server_addr.sin_port = htons(port);
|
|
if (tls_socket_bind(sock, &server_addr) != 1) {
|
|
fprintf(stderr, "%s: socket bind error\n", prog);
|
|
goto end;
|
|
}
|
|
|
|
client_addr_len = sizeof(client_addr);
|
|
n = recvfrom(sock, (char *)buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
|
|
if (n <= 0) {
|
|
fprintf(stderr, "%s: recvfrom error\n", prog);
|
|
goto end;
|
|
}
|
|
if (verbose) {
|
|
fprintf(stderr, "recv UDP datagram: %ld bytes\n", (long)n);
|
|
quic_packet_print(stderr, 0, 0, buf, (size_t)n);
|
|
}
|
|
|
|
{
|
|
const uint8_t *odcid;
|
|
const uint8_t *client_scid;
|
|
size_t odcid_len;
|
|
size_t client_scid_len;
|
|
if (quic_long_packet_connection_ids_get(buf, (size_t)n, &odcid, &odcid_len, &client_scid, &client_scid_len) != 1
|
|
|| odcid_len > sizeof(server_dcid) || client_scid_len > sizeof(server_dcid)) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
memcpy(server_dcid, client_scid, client_scid_len);
|
|
server_dcid_len = client_scid_len;
|
|
if (quic_derive_initial_secrets(odcid, odcid_len, &initial_secrets) != 1
|
|
|| quic_derive_initial_client_keys(&initial_secrets, &initial_client_keys0) != 1
|
|
|| quic_derive_initial_server_keys(&initial_secrets, &initial_server_keys0) != 1
|
|
|| quic_packet_keys_from_initial(&initial_client_keys0, &initial_client_keys) != 1
|
|
|| quic_packet_keys_from_initial(&initial_server_keys0, &initial_server_keys) != 1
|
|
|| quic_long_packet_decrypt(&initial_client_keys, buf, (size_t)n, QUIC_packet_initial, &decrypted) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
}
|
|
if (verbose) {
|
|
format_print(stderr, 0, 0, "Decrypted Client Initial Packet\n");
|
|
format_print(stderr, 0, 4, "Packet Number: %llu\n", (unsigned long long)decrypted.packet_number);
|
|
quic_frames_print(stderr, 0, 4, QUIC_encryption_initial, decrypted.plaintext, decrypted.plaintext_len);
|
|
}
|
|
if (quic_frames_crypto_collect(decrypted.plaintext, decrypted.plaintext_len,
|
|
initial_crypto, &initial_crypto_len, sizeof(initial_crypto), &largest_ack) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
while (!quic_tls_handshake_is_complete(initial_crypto, initial_crypto_len)) {
|
|
n = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
|
|
if (n <= 0) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
if (verbose) {
|
|
fprintf(stderr, "recv UDP datagram: %ld bytes\n", (long)n);
|
|
quic_packet_print(stderr, 0, 0, buf, (size_t)n);
|
|
}
|
|
if (quic_long_packet_decrypt(&initial_client_keys, buf, (size_t)n, QUIC_packet_initial, &decrypted) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
if (verbose) {
|
|
format_print(stderr, 0, 0, "Decrypted Client Initial Packet\n");
|
|
format_print(stderr, 0, 4, "Packet Number: %llu\n", (unsigned long long)decrypted.packet_number);
|
|
quic_frames_print(stderr, 0, 4, QUIC_encryption_initial, decrypted.plaintext, decrypted.plaintext_len);
|
|
}
|
|
if (quic_frames_crypto_collect(decrypted.plaintext, decrypted.plaintext_len,
|
|
initial_crypto, &initial_crypto_len, sizeof(initial_crypto), &largest_ack) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
}
|
|
if (quic_server_client_hello_process(&conn, initial_crypto, initial_crypto_len) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
|
|
quic_transport_params_init(¶ms);
|
|
if (quic_transport_params_add(¶ms, QUIC_transport_param_original_destination_connection_id, decrypted.dcid, decrypted.dcid_len) != 1
|
|
|| quic_transport_params_add(¶ms, QUIC_transport_param_initial_source_connection_id, server_scid, server_scid_len) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_max_udp_payload_size, 1200) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_initial_max_data, 1048576) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_initial_max_stream_data_bidi_remote, 262144) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_initial_max_stream_data_uni, 262144) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_initial_max_streams_bidi, 100) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_initial_max_streams_uni, 3) != 1
|
|
|| quic_transport_params_add_varint(¶ms, QUIC_transport_param_active_connection_id_limit, 2) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
|
|
p = server_initial_crypto;
|
|
if (quic_server_hello_to_bytes(&conn, &p, &server_initial_crypto_len) != 1
|
|
|| quic_packet_keys_derive(conn.digest, conn.client_handshake_traffic_secret, conn.cipher_suite, &client_handshake_keys) != 1
|
|
|| quic_packet_keys_derive(conn.digest, conn.server_handshake_traffic_secret, conn.cipher_suite, &server_handshake_keys) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
p = server_handshake_crypto;
|
|
if (quic_server_encrypted_extensions_to_bytes(&conn, ¶ms, &p, &server_handshake_crypto_len) != 1
|
|
|| quic_server_certificate_to_bytes(&conn, &p, &server_handshake_crypto_len) != 1
|
|
|| quic_server_certificate_verify_to_bytes(&conn, &p, &server_handshake_crypto_len) != 1
|
|
|| quic_server_finished_to_bytes(&conn, &p, &server_handshake_crypto_len) != 1
|
|
|| quic_packet_keys_derive(conn.digest, conn.server_application_traffic_secret, conn.cipher_suite, &server_application_keys) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
|
|
p = frames;
|
|
frames_len = 0;
|
|
if (quic_ack_frame_to_bytes(decrypted.packet_number, &p, &frames_len) != 1
|
|
|| quic_crypto_frame_to_bytes(0, server_initial_crypto, server_initial_crypto_len, &p, &frames_len) != 1
|
|
|| quic_long_packet_encrypt(&initial_server_keys, QUIC_packet_initial, server_dcid, server_dcid_len,
|
|
server_scid, server_scid_len, 0, frames, frames_len, packet, &packet_len) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
memcpy(sendbuf, packet, packet_len);
|
|
{
|
|
size_t sendbuf_len = packet_len;
|
|
p = frames;
|
|
frames_len = 0;
|
|
if (quic_crypto_frame_to_bytes(0, server_handshake_crypto, server_handshake_crypto_len, &p, &frames_len) != 1
|
|
|| quic_long_packet_encrypt(&server_handshake_keys, QUIC_packet_handshake, server_dcid, server_dcid_len,
|
|
server_scid, server_scid_len, 0, frames, frames_len, packet, &packet_len) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
memcpy(sendbuf + sendbuf_len, packet, packet_len);
|
|
sendbuf_len += packet_len;
|
|
if (verbose) {
|
|
fprintf(stderr, "send QUIC Initial+Handshake flight: %zu bytes\n", sendbuf_len);
|
|
}
|
|
if (sendto(sock, (const char *)sendbuf, sendbuf_len, 0, (struct sockaddr *)&client_addr, client_addr_len) != (tls_ret_t)sendbuf_len) {
|
|
fprintf(stderr, "%s: sendto handshake flight error\n", prog);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
for (;;) {
|
|
size_t off = 0;
|
|
client_addr_len = sizeof(client_addr);
|
|
n = recvfrom(sock, (char *)buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
|
|
if (n <= 0) {
|
|
fprintf(stderr, "%s: recvfrom error\n", prog);
|
|
goto end;
|
|
}
|
|
if (verbose) {
|
|
fprintf(stderr, "recv UDP datagram: %ld bytes\n", (long)n);
|
|
quic_packet_print(stderr, 0, 0, buf, (size_t)n);
|
|
}
|
|
while (off < (size_t)n) {
|
|
size_t current_len;
|
|
if (quic_packet_total_length(buf + off, (size_t)n - off, ¤t_len) != 1 || !current_len) {
|
|
break;
|
|
}
|
|
if ((buf[off] & 0x80) && ((buf[off] >> 4) & 0x03) == QUIC_packet_handshake) {
|
|
if (quic_long_packet_decrypt(&client_handshake_keys, buf + off, current_len, QUIC_packet_handshake, &decrypted) == 1) {
|
|
handshake_crypto_len = 0;
|
|
largest_ack = 0;
|
|
if (quic_frames_crypto_collect(decrypted.plaintext, decrypted.plaintext_len,
|
|
handshake_crypto, &handshake_crypto_len, sizeof(handshake_crypto), &largest_ack) != 1
|
|
|| quic_server_client_finished_process(&conn, handshake_crypto, handshake_crypto_len) != 1
|
|
|| quic_packet_keys_derive(conn.digest, conn.client_application_traffic_secret, conn.cipher_suite, &client_application_keys) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
if (verbose) {
|
|
fprintf(stderr, "QUIC TLS handshake completed\n");
|
|
}
|
|
}
|
|
} else if (!(buf[off] & 0x80)) {
|
|
if (quic_short_packet_decrypt(&client_application_keys, buf + off, current_len,
|
|
server_scid, server_scid_len, &decrypted) == 1) {
|
|
if (verbose) {
|
|
format_print(stderr, 0, 0, "Decrypted 1-RTT Packet\n");
|
|
format_print(stderr, 0, 4, "Packet Number: %llu\n", (unsigned long long)decrypted.packet_number);
|
|
quic_frames_print(stderr, 0, 4, QUIC_encryption_application, decrypted.plaintext, decrypted.plaintext_len);
|
|
}
|
|
if (quic_application_request_stream_id(decrypted.plaintext, decrypted.plaintext_len, NULL, &request_stream_id) == 1) {
|
|
const uint8_t body[] = "hello from gmssl quic server\n";
|
|
if (quic_http3_response_to_frames(request_stream_id, body, sizeof(body) - 1,
|
|
decrypted.packet_number, frames, &frames_len) != 1
|
|
|| quic_short_packet_encrypt(&server_application_keys, server_dcid, server_dcid_len,
|
|
0, frames, frames_len, packet, &packet_len) != 1) {
|
|
error_print();
|
|
goto end;
|
|
}
|
|
if (verbose) {
|
|
fprintf(stderr, "send QUIC 1-RTT HTTP/3 response: %zu bytes\n", packet_len);
|
|
quic_frames_print(stderr, 0, 4, QUIC_encryption_application, frames, frames_len);
|
|
}
|
|
if (sendto(sock, (const char *)packet, packet_len, 0, (struct sockaddr *)&client_addr, client_addr_len) != (tls_ret_t)packet_len) {
|
|
fprintf(stderr, "%s: sendto response error\n", prog);
|
|
goto end;
|
|
}
|
|
ret = 0;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
off += current_len;
|
|
}
|
|
}
|
|
|
|
end:
|
|
if (tls_socket_is_valid(sock)) {
|
|
tls_socket_close(sock);
|
|
}
|
|
tls_ctx_cleanup(&ctx);
|
|
tls_socket_lib_cleanup();
|
|
return ret;
|
|
}
|