Files
GmSSL/tools/quic_server.c
2026-06-26 14:23:08 +08:00

1019 lines
35 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/mem.h>
#include <gmssl/quic.h>
#include <gmssl/tls.h>
#include <gmssl/socket.h>
#include <gmssl/error.h>
#include "passwd.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, prompt if not given\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;
char passbuf[GMSSL_PASSWORD_MAX_SIZE] = {0};
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;
}
if (gmssl_tool_get_password(prog, "Password to decrypt private key", keyfile, &pass,
passbuf, sizeof(passbuf)) != 1) {
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) != 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(&params);
if (quic_transport_params_add(&params, QUIC_transport_param_original_destination_connection_id, decrypted.dcid, decrypted.dcid_len) != 1
|| quic_transport_params_add(&params, QUIC_transport_param_initial_source_connection_id, server_scid, server_scid_len) != 1
|| quic_transport_params_add_varint(&params, QUIC_transport_param_max_udp_payload_size, 1200) != 1
|| quic_transport_params_add_varint(&params, QUIC_transport_param_initial_max_data, 1048576) != 1
|| quic_transport_params_add_varint(&params, QUIC_transport_param_initial_max_stream_data_bidi_remote, 262144) != 1
|| quic_transport_params_add_varint(&params, QUIC_transport_param_initial_max_stream_data_uni, 262144) != 1
|| quic_transport_params_add_varint(&params, QUIC_transport_param_initial_max_streams_bidi, 100) != 1
|| quic_transport_params_add_varint(&params, QUIC_transport_param_initial_max_streams_uni, 3) != 1
|| quic_transport_params_add_varint(&params, 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, &params, &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, &current_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:
gmssl_secure_clear(passbuf, sizeof(passbuf));
if (tls_socket_is_valid(sock)) {
tls_socket_close(sock);
}
tls_ctx_cleanup(&ctx);
tls_socket_lib_cleanup();
return ret;
}