Update TLS 1.3

Cross-validation with OpenSSL
This commit is contained in:
Zhi Guan
2026-05-21 14:23:35 +08:00
parent 8e8819f27d
commit 431a22e2e9
7 changed files with 153 additions and 61 deletions

View File

@@ -49,6 +49,8 @@ int secp256r1_private_key_info_decrypt_from_der(SECP256R1_KEY *ec_key,
const uint8_t **attrs, size_t *attrs_len,
const char *pass, const uint8_t **in, size_t *inlen);
int secp256r1_private_key_to_pem(const SECP256R1_KEY *key, FILE *fp);
int secp256r1_private_key_from_pem(SECP256R1_KEY *key, FILE *fp);
int secp256r1_private_key_info_encrypt_to_pem(const SECP256R1_KEY *key, const char *pass, FILE *fp);
int secp256r1_private_key_info_decrypt_from_pem(SECP256R1_KEY *key, const char *pass, FILE *fp);

View File

@@ -541,8 +541,38 @@ int secp256r1_private_key_info_decrypt_from_pem(SECP256R1_KEY *key, const char *
return 1;
}
// FIXME: side-channel of Base64
int secp256r1_private_key_to_pem(const SECP256R1_KEY *a, FILE *fp)
{
uint8_t buf[512];
uint8_t *p = buf;
size_t len = 0;
if (secp256r1_private_key_to_der(a, &p, &len) != 1) {
error_print();
return -1;
}
if (pem_write(fp, "EC PRIVATE KEY", buf, len) <= 0) {
error_print();
return -1;
}
return 1;
}
int secp256r1_private_key_from_pem(SECP256R1_KEY *a, FILE *fp)
{
uint8_t buf[512];
const uint8_t *cp = buf;
size_t len;
if (pem_read(fp, "EC PRIVATE KEY", buf, &len, sizeof(buf)) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_from_der(a, &cp, &len) != 1
|| len > 0) {
error_print();
return -1;
}
return 1;
}

View File

@@ -281,6 +281,28 @@ int tls13_record_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t iv[12],
}
int tls13_hkdf_extract(const DIGEST *digest, const uint8_t salt[32], const uint8_t in[32], uint8_t out[32])
{
size_t saltlen;
size_t inlen;
size_t outlen;
if (!digest || !salt || !in || !out) {
error_print();
return -1;
}
saltlen = digest->digest_size;
inlen = digest->digest_size;
if (hkdf_extract(digest, salt, saltlen, in, inlen, out, &outlen) != 1) {
error_print();
return -1;
}
// outlen == digest->digest_size
return 1;
}
/*
HKDF-Expand-Label(Secret, Label, Context, Length) =
HKDF-Expand(Secret, HkdfLabel, Length);
@@ -289,68 +311,70 @@ HKDF-Expand-Label(Secret, Label, Context, Length) =
uint16 length = Length;
opaque label<7..255> = "tls13 " + Label;
opaque context<0..255> = Context; }
Derive-Secret(Secret, Label, Messages) =
HKDF-Expand-Label(Secret, Label, Hash(Messages), Hash.length)
*/
// TLS 1.3 的密钥生成过程都是通过HKDF-Extract和Derive-Secret这两个函数实现的
// HKDF-Extract 的输出长度完全是由哈希长度决定的,输出是 Derive-Secret 的输入
// Derive-Secret 的输出长度也是由哈希长度决定的
// 这个函数掩盖了hkdf_extract并且假定使用的哈希函数的哈希值的长度是32这个没有必要并且不清晰
int tls13_hkdf_extract(const DIGEST *digest, const uint8_t salt[32], const uint8_t in[32], uint8_t out[32])
{
size_t dgstlen;
if (hkdf_extract(digest, salt, 32, in, 32, out, &dgstlen) != 1
|| dgstlen != 32) {
error_print();
return -1;
}
return 1;
}
// 增加secret_len作为输入的参数
// Expand-Label
int tls13_hkdf_expand_label(const DIGEST *digest, const uint8_t secret[32],
const char *label, const uint8_t *context, size_t context_len,
size_t outlen, uint8_t *out)
{
uint8_t label_len;
uint8_t hkdf_label[2 + 256 + 256];
uint8_t *p = hkdf_label;
size_t hkdf_label_len = 0;
size_t secret_len;
size_t label_len;
if (!digest || !secret || !label || !outlen || !out) {
error_print();
return -1;
}
if (strlen(label) > 255 - strlen("tls13 ")) {
error_print();
return -1;
}
if (outlen > 65535) {
error_print();
return -1;
}
secret_len = digest->digest_size;
label_len = strlen("tls13 ") + strlen(label);
label_len = (uint8_t)(strlen("tls13 ") + strlen(label)); //FIXME: check length < 255
tls_uint16_to_bytes((uint16_t)outlen, &p, &hkdf_label_len);
tls_uint8_to_bytes(label_len, &p, &hkdf_label_len);
tls_uint8_to_bytes((uint8_t)label_len, &p, &hkdf_label_len);
tls_array_to_bytes((uint8_t *)"tls13 ", strlen("tls13 "), &p, &hkdf_label_len);
tls_array_to_bytes((uint8_t *)label, strlen(label), &p, &hkdf_label_len);
tls_uint8array_to_bytes(context, context_len, &p, &hkdf_label_len);
hkdf_expand(digest, secret, 32, hkdf_label, hkdf_label_len, outlen, out);
// format_bytes(stderr, 0, 0, "HkdfLabel", hkdf_label, hkdf_label_len);
hkdf_expand(digest, secret, secret_len, hkdf_label, hkdf_label_len, outlen, out);
return 1;
}
// 增加secret_len
// 输出长度是由digest决定的应该提供一个输出长度 outlen
/*
Derive-Secret(Secret, Label, Messages) =
HKDF-Expand-Label(Secret, Label, Hash(Messages), Hash.length)
一般来说derive_secret的输入是message但是传递给下面的是hash但是我们这里直接传递了hash
*/
int tls13_derive_secret(const uint8_t secret[32], const char *label, const DIGEST_CTX *dgst_ctx, uint8_t out[32])
{
DIGEST_CTX ctx = *dgst_ctx;
uint8_t dgst[64];
size_t dgstlen;
size_t outlen = 32;
uint8_t context[32];
size_t context_len;
if (digest_finish(&ctx, dgst, &dgstlen) != 1) {
if (digest_finish(&ctx, context, &context_len) != 1) {
error_print();
return -1;
}
if (tls13_hkdf_expand_label(dgst_ctx->digest, secret, label, dgst, 32, dgstlen, out) != 1) {
// 这个值是对的
//context_len = 0;
if (tls13_hkdf_expand_label(dgst_ctx->digest, secret, label, context, context_len, outlen, out) != 1) {
error_print();
return -1;
}
@@ -361,6 +385,14 @@ int tls13_derive_secret(const uint8_t secret[32], const char *label, const DIGES
/*
如果early_secret是对的那么应该首先从early_secret 生成一个derived_secret
然后再用derived_secret和ecdhe生成handshake_secret
但是在openssl中这两个步骤被合并到一起了不知道具体是怎么做的
0
|
v
@@ -454,7 +486,7 @@ int tls13_generate_early_keys(TLS_CONNECT *conn)
block_cipher_set_encrypt_key(&conn->client_write_key, conn->cipher, client_write_key);
tls_seq_num_reset(conn->client_seq_num);
format_print(stderr, 0, 0, "generate early_keys\n");
format_print(stderr, 0, 0, "generate_early_keys\n");
format_bytes(stderr, 0, 4, "early_secret", conn->early_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "client_early_traffic_secret", conn->client_early_traffic_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "client_write_key", client_write_key, client_write_key_len);
@@ -468,8 +500,9 @@ int tls13_generate_early_keys(TLS_CONNECT *conn)
int tls13_generate_handshake_secrets(TLS_CONNECT *conn)
{
const uint8_t zeros[32] = {0};
uint8_t pre_master_secret[32] = {0};
size_t pre_master_secret_len;
uint8_t ecdhe_shared_secret[32];
size_t ecdhe_shared_secret_len;
uint8_t derived_secret[32];
DIGEST_CTX null_dgst_ctx;
if (!conn || !conn->digest) {
@@ -485,7 +518,7 @@ int tls13_generate_handshake_secrets(TLS_CONNECT *conn)
}
if (x509_key_exchange(&conn->key_exchanges[conn->key_exchange_idx],
conn->peer_key_exchange, conn->peer_key_exchange_len,
pre_master_secret, &pre_master_secret_len) != 1) {
ecdhe_shared_secret, &ecdhe_shared_secret_len) != 1) {
error_print();
return -1;
}
@@ -497,19 +530,21 @@ int tls13_generate_handshake_secrets(TLS_CONNECT *conn)
}
/* [1] */ tls13_hkdf_extract(conn->digest, zeros, conn->psk, conn->early_secret);
/* [5] */ tls13_derive_secret(conn->early_secret, "derived", &null_dgst_ctx, conn->handshake_secret);
/* [6] */ tls13_hkdf_extract(conn->digest, conn->handshake_secret, conn->pre_master_secret, conn->handshake_secret);
/* [5] */ tls13_derive_secret(conn->early_secret, "derived", &null_dgst_ctx, derived_secret);
/* [6] */ tls13_hkdf_extract(conn->digest, derived_secret, ecdhe_shared_secret, conn->handshake_secret);
/* [7] */ tls13_derive_secret(conn->handshake_secret, "c hs traffic", &conn->dgst_ctx, conn->client_handshake_traffic_secret);
/* [8] */ tls13_derive_secret(conn->handshake_secret, "s hs traffic", &conn->dgst_ctx, conn->server_handshake_traffic_secret);
format_print(stderr, 0, 0, "generate handshake_secrets\n");
format_print(stderr, 0, 0, "generate_handshake_secrets\n");
format_bytes(stderr, 0, 4, "early_secret", conn->early_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "pre_master_secret", pre_master_secret, pre_master_secret_len);
format_bytes(stderr, 0, 4, "handshake_secret", conn->handshake_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "derived_secret", derived_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "ecdhe_shared_secret", ecdhe_shared_secret, ecdhe_shared_secret_len);
format_bytes(stderr, 0, 4, "handshake_secret",conn->handshake_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "client_handshake_traffic_secret", conn->client_handshake_traffic_secret, conn->digest->digest_size);
format_bytes(stderr, 0, 4, "server_handshake_traffic_secret", conn->server_handshake_traffic_secret, conn->digest->digest_size);
gmssl_secure_clear(pre_master_secret, sizeof(pre_master_secret));
gmssl_secure_clear(ecdhe_shared_secret, sizeof(ecdhe_shared_secret));
gmssl_secure_clear(derived_secret, sizeof(derived_secret));
return 1;
}
@@ -531,7 +566,7 @@ int tls13_generate_master_secret(TLS_CONNECT *conn)
/* [9] */ tls13_derive_secret(conn->handshake_secret, "derived", &null_dgst_ctx, conn->master_secret);
/* [10] */ tls13_hkdf_extract(conn->digest, conn->master_secret, zeros, conn->master_secret);
format_print(stderr, 0, 0, "generate master_secret\n");
format_print(stderr, 0, 0, "generate_master_secret\n");
format_bytes(stderr, 0, 4, "master_secret", conn->master_secret, conn->digest->digest_size);
return 1;
}
@@ -553,7 +588,7 @@ int tls13_generate_client_handshake_keys(TLS_CONNECT *conn)
block_cipher_set_encrypt_key(&conn->client_write_key, conn->cipher, client_write_key);
tls_seq_num_reset(conn->client_seq_num);
format_print(stderr, 0, 0, "generate client_handshake_keys\n");
format_print(stderr, 0, 0, "generate_client_handshake_keys\n");
format_bytes(stderr, 0, 4, "client_write_key", client_write_key, client_write_key_len);
format_bytes(stderr, 0, 4, "client_write_iv", conn->client_write_iv, TLS13_IV_SIZE);
format_print(stderr, 0, 4, "client_seq_num: %"PRIu64"\n", GETU64(conn->client_seq_num));
@@ -579,7 +614,7 @@ int tls13_generate_server_handshake_keys(TLS_CONNECT *conn)
block_cipher_set_encrypt_key(&conn->server_write_key, conn->cipher, server_write_key);
tls_seq_num_reset(conn->server_seq_num);
format_print(stderr, 0, 0, "generate server_handshake_keys\n");
format_print(stderr, 0, 0, "generate_server_handshake_keys\n");
format_bytes(stderr, 0, 4, "server_write_key", server_write_key, server_write_key_len);
format_bytes(stderr, 0, 4, "server_write_iv", conn->server_write_iv, TLS13_IV_SIZE);
format_print(stderr, 0, 4, "server_seq_num: %"PRIu64"\n", GETU64(conn->server_seq_num));
@@ -614,7 +649,7 @@ int tls13_update_client_application_secret(TLS_CONNECT *conn)
tls13_hkdf_expand_label(conn->digest, conn->client_application_traffic_secret, "traffic upd", NULL, 0,
conn->digest->digest_size, conn->client_application_traffic_secret);
format_print(stderr, 0, 0, "update client_application_secret\n");
format_print(stderr, 0, 0, "update_client_application_secret\n");
format_bytes(stderr, 0, 4, "client_application_traffic_secret", conn->client_application_traffic_secret, conn->digest->digest_size);
return 1;
}
@@ -629,7 +664,7 @@ int tls13_update_server_application_secret(TLS_CONNECT *conn)
tls13_hkdf_expand_label(conn->digest, conn->server_application_traffic_secret, "traffic upd", NULL, 0,
conn->digest->digest_size, conn->server_application_traffic_secret);
format_print(stderr, 0, 0, "update server_application_secret\n");
format_print(stderr, 0, 0, "update_server_application_secret\n");
format_bytes(stderr, 0, 4, "server_application_traffic_secret", conn->server_application_traffic_secret, conn->digest->digest_size);
return 1;
}
@@ -651,7 +686,7 @@ int tls13_generate_client_application_keys(TLS_CONNECT *conn)
block_cipher_set_encrypt_key(&conn->client_write_key, conn->cipher, client_write_key);
tls_seq_num_reset(conn->client_seq_num);
format_print(stderr, 0, 0, "update client_application_keys\n");
format_print(stderr, 0, 0, "update_client_application_keys\n");
format_bytes(stderr, 0, 4, "client_write_key", client_write_key, client_write_key_len);
format_bytes(stderr, 0, 4, "client_write_iv", conn->client_write_iv, TLS13_IV_SIZE);
format_print(stderr, 0, 4, "client_seq_num: %"PRIu64"\n", GETU64(conn->client_seq_num));
@@ -677,7 +712,7 @@ int tls13_generate_server_application_keys(TLS_CONNECT *conn)
block_cipher_set_encrypt_key(&conn->server_write_key, conn->cipher, server_write_key);
tls_seq_num_reset(conn->server_seq_num);
format_print(stderr, 0, 0, "update server_application_keys\n");
format_print(stderr, 0, 0, "update_server_application_keys\n");
format_bytes(stderr, 0, 4, "server_write_key", server_write_key, server_write_key_len);
format_bytes(stderr, 0, 4, "server_write_iv", conn->server_write_iv, TLS13_IV_SIZE);
format_print(stderr, 0, 4, "server_seq_num: %"PRIu64"\n", GETU64(conn->server_seq_num));

View File

@@ -1890,6 +1890,8 @@ int x509_cert_check(const uint8_t *cert, size_t certlen, int cert_type,
return 1;
}
// 这个函数应该打印到底是哪个证书验证出错了
int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type,
const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result)
{

View File

@@ -158,7 +158,7 @@ static const char *options =
" cmssign Generate CMS SignedData\n"
" cmsverify Verify CMS SignedData\n"
#ifdef ENABLE_SECP256R1
" p256keygen Generate P-256 (secp256r1, prime256v1) keypair\n"
" p256keygen Generate P-256 (secp256r1, prime256v1) keypair\n"
#endif
#ifdef ENABLE_LMS
" lmskeygen Generate LMS-SM3 (Leighton-Micali Signature) keypair\n"

View File

@@ -24,6 +24,7 @@ static const char *options =
" -pass pass Password to encrypt the private key\n"
" -out pem Output password-encrypted PKCS #8 private key in PEM format\n"
" -pubout pem Output public key in PEM format\n"
" -export pem Output non-encrypted PKCS#8 private key in PEM format\n"
"\n"
"Examples\n"
"\n"
@@ -38,8 +39,10 @@ int p256keygen_main(int argc, char **argv)
char *pass = NULL;
char *outfile = NULL;
char *puboutfile = NULL;
char *exportfile = NULL;
FILE *outfp = stdout;
FILE *puboutfp = stdout;
FILE *exportfp = NULL;
int curve_oid = OID_secp256r1;
X509_KEY key;
@@ -71,7 +74,14 @@ int p256keygen_main(int argc, char **argv)
if (--argc < 1) goto bad;
puboutfile = *(++argv);
if (!(puboutfp = fopen(puboutfile, "wb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, puboutfile, strerror(errno));
goto end;
}
} else if (!strcmp(*argv, "-export")) {
if (--argc < 1) goto bad;
exportfile = *(++argv);
if (!(exportfp = fopen(exportfile, "wb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, exportfile, strerror(errno));
goto end;
}
} else {
@@ -91,7 +101,6 @@ bad:
goto end;
}
if (x509_key_generate(&key, OID_ec_public_key, &curve_oid, sizeof(curve_oid)) != 1) {
fprintf(stderr, "gmssl %s: inner failure\n", prog);
return -1;
@@ -104,6 +113,13 @@ bad:
fprintf(stderr, "gmssl %s: inner failure\n", prog);
goto end;
}
if (exportfp) {
if (secp256r1_private_key_to_pem(&key.u.secp256r1_key, exportfp) != 1) {
fprintf(stderr, "gmssl %s: inner failure\n", prog);
goto end;
}
}
ret = 0;
end:

View File

@@ -33,6 +33,8 @@
// 或者P256的私钥应该用AES-128 + SHA-256加密
// 应该首先打印openssl的密钥序列early_secret, pre_master_secret, 以及 handshake_secret 等
static const char *options = "[-port num] -cert file -key file -pass str [-cacert file]";
@@ -109,12 +111,12 @@ static const char *help =
"\n"
"Generate P-256 certificates\n"
"\n"
" gmssl p256keygen -pass 1234 -out p256rootcakey.pem\n"
" gmssl p256keygen -pass 1234 -out p256rootcakey.pem -export p256rootcakey.exp\n"
" gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN P256ROOTCA -days 3650 \\\n"
" -key p256rootcakey.pem -pass 1234 -out p256rootcacert.pem \\\n"
" -key_usage keyCertSign -key_usage cRLSign -ca\n"
"\n"
" gmssl p256keygen -pass 1234 -out p256cakey.pem\n"
" gmssl p256keygen -pass 1234 -out p256cakey.pem -export p256cakey.exp\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN \"P256 Sub CA\" \\\n"
" -key p256cakey.pem -pass 1234 -out p256careq.pem\n"
" gmssl reqsign -in p256careq.pem -days 365 -key_usage keyCertSign \\\n"
@@ -122,7 +124,7 @@ static const char *help =
" -ca -path_len_constraint 0 \\\n"
" -out p256cacert.pem\n"
"\n"
" gmssl p256keygen -pass 1234 -out p256signkey.pem\n"
" gmssl p256keygen -pass 1234 -out p256signkey.pem -export p256signkey.exp\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN 127.0.0.1 \\\n"
" -key p256signkey.pem -pass 1234 -out p256signreq.pem\n"
" gmssl reqsign -in p256signreq.pem -days 365 -key_usage digitalSignature \\\n"
@@ -144,6 +146,11 @@ static const char *help =
" gmssl tls13_client -host 127.0.0.1 -port 4430 -cacert rootcacerts.pem \\\n"
" -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 -sig_alg ecdsa_secp256r1_sha256\n"
"\n"
" add `SSL_CTX_clear_options(ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);` to openssl apps/s_server.c\n"
" /usr/local/bin/openssl s_server -accept 4430 -cert p256signcert.pem -cert_chain p256cacert.pem -key p256signkey.exp \\\n"
" -tls1_3 -ciphersuites TLS_AES_128_GCM_SHA256 -named_curve prime256v1 \\\n"
" -trace -keylogfile sslkeys.log\n"
"\n"
"TLS 1.3 SNI\n"
"\n"
" sudo gmssl tls13_server -port 4430 \\\n"