From 174d6efef4ebe678f212ff94c2f171b6e5e004c5 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 13 Oct 2023 16:22:59 +0200 Subject: [PATCH 01/67] Avoid another copy of key schedule pointer in PROV_GCM_CTX This copy would need an update on dupctx but rather than doing it just remove the copy. This fixes failures of evp_test on Windows with new CPUs. Reviewed-by: Todd Short Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22384) Signed-off-by: fly2x --- .../ciphers/cipher_aes_gcm_hw_vaes_avx512.inc | 7 +++---- providers/implementations/ciphers/cipher_sm4_gcm_hw.c | 1 - providers/implementations/include/prov/ciphercommon_gcm.h | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc index ef18677979..c892c0754e 100644 --- a/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc @@ -48,7 +48,6 @@ static int vaes_gcm_setkey(PROV_GCM_CTX *ctx, const unsigned char *key, PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; AES_KEY *ks = &actx->ks.ks; - ctx->ks = ks; aesni_set_encrypt_key(key, keylen * 8, ks); memset(gcmctx, 0, sizeof(*gcmctx)); gcmctx->key = ks; @@ -77,7 +76,7 @@ static int vaes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, if (ivlen > (U64(1) << 61)) return 0; - ossl_aes_gcm_setiv_avx512(ctx->ks, gcmctx, iv, ivlen); + ossl_aes_gcm_setiv_avx512(gcmctx->key, gcmctx, iv, ivlen); return 1; } @@ -162,9 +161,9 @@ static int vaes_gcm_cipherupdate(PROV_GCM_CTX *ctx, const unsigned char *in, } if (ctx->enc) - ossl_aes_gcm_encrypt_avx512(ctx->ks, gcmctx, &gcmctx->mres, in, len, out); + ossl_aes_gcm_encrypt_avx512(gcmctx->key, gcmctx, &gcmctx->mres, in, len, out); else - ossl_aes_gcm_decrypt_avx512(ctx->ks, gcmctx, &gcmctx->mres, in, len, out); + ossl_aes_gcm_decrypt_avx512(gcmctx->key, gcmctx, &gcmctx->mres, in, len, out); return 1; } diff --git a/providers/implementations/ciphers/cipher_sm4_gcm_hw.c b/providers/implementations/ciphers/cipher_sm4_gcm_hw.c index 432e3589ed..630d8a3218 100644 --- a/providers/implementations/ciphers/cipher_sm4_gcm_hw.c +++ b/providers/implementations/ciphers/cipher_sm4_gcm_hw.c @@ -15,7 +15,6 @@ #include "crypto/sm4_platform.h" # define SM4_GCM_HW_SET_KEY_CTR_FN(ks, fn_set_enc_key, fn_block, fn_ctr) \ - ctx->ks = ks; \ fn_set_enc_key(key, ks); \ CRYPTO_gcm128_init(&ctx->gcm, ks, (block128_f)fn_block); \ ctx->ctr = (ctr128_f)fn_ctr; \ diff --git a/providers/implementations/include/prov/ciphercommon_gcm.h b/providers/implementations/include/prov/ciphercommon_gcm.h index 3aacf91c8b..ee0b23b927 100644 --- a/providers/implementations/include/prov/ciphercommon_gcm.h +++ b/providers/implementations/include/prov/ciphercommon_gcm.h @@ -79,7 +79,6 @@ typedef struct prov_gcm_ctx_st { const PROV_GCM_HW *hw; /* hardware specific methods */ GCM128_CONTEXT gcm; ctr128_f ctr; - const void *ks; } PROV_GCM_CTX; PROV_CIPHER_FUNC(int, GCM_setkey, (PROV_GCM_CTX *ctx, const unsigned char *key, @@ -126,7 +125,6 @@ int ossl_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in, size_t len, unsigned char *out); # define GCM_HW_SET_KEY_CTR_FN(ks, fn_set_enc_key, fn_block, fn_ctr) \ - ctx->ks = ks; \ fn_set_enc_key(key, keylen * 8, ks); \ CRYPTO_gcm128_init(&ctx->gcm, ks, (block128_f)fn_block); \ ctx->ctr = (ctr128_f)fn_ctr; \ -- Gitee From d4a3a5b29b1de06d499fd5b4bd9282e1100d085d Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 13 Oct 2023 22:30:31 +0200 Subject: [PATCH 02/67] PKCS7_SIGNER_INFO: point out confusing names of digest_enc_alg and enc_digest fields Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22390) Signed-off-by: fly2x --- include/openssl/pkcs7.h.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openssl/pkcs7.h.in b/include/openssl/pkcs7.h.in index 127d6afea8..57e45dc2fb 100644 --- a/include/openssl/pkcs7.h.in +++ b/include/openssl/pkcs7.h.in @@ -60,8 +60,8 @@ typedef struct pkcs7_signer_info_st { PKCS7_ISSUER_AND_SERIAL *issuer_and_serial; X509_ALGOR *digest_alg; STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */ - X509_ALGOR *digest_enc_alg; - ASN1_OCTET_STRING *enc_digest; + X509_ALGOR *digest_enc_alg; /* confusing name, actually used for signing */ + ASN1_OCTET_STRING *enc_digest; /* confusing name, actually signature */ STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */ /* The private key to sign with */ EVP_PKEY *pkey; -- Gitee From 5e3fb66abcf11be660e787798816c5152859262a Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 13 Oct 2023 22:39:25 +0200 Subject: [PATCH 03/67] CMS_add1_signer.pod: add missing info on CMS_SignerInfo_sign() return values Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22390) Signed-off-by: fly2x --- doc/man3/CMS_add1_signer.pod | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/man3/CMS_add1_signer.pod b/doc/man3/CMS_add1_signer.pod index 800085b7b8..11afecb905 100644 --- a/doc/man3/CMS_add1_signer.pod +++ b/doc/man3/CMS_add1_signer.pod @@ -31,8 +31,8 @@ Unless the B flag is set the returned CMS_ContentInfo structure is not complete and must be finalized either by streaming (if applicable) or a call to CMS_final(). -The CMS_SignerInfo_sign() function will explicitly sign a CMS_SignerInfo -structure, its main use is when B and B flags +The CMS_SignerInfo_sign() function explicitly signs a CMS_SignerInfo +structure, its main use is when the B and B flags are both set. =head1 NOTES @@ -90,6 +90,8 @@ before it is finalized. CMS_add1_signer() returns an internal pointer to the CMS_SignerInfo structure just added or NULL if an error occurs. +CMS_SignerInfo_sign() returns 1 on success, 0 on failure. + =head1 SEE ALSO L, L, -- Gitee From 3986b31977e84e4464b5189c1174c47758d736cc Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 13 Oct 2023 22:12:22 +0200 Subject: [PATCH 04/67] CMS_add1_signer(): add missing ERR_raise() calls Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22390) Signed-off-by: fly2x --- crypto/cms/cms_err.c | 4 +++- crypto/cms/cms_sd.c | 13 ++++++++++--- crypto/err/openssl.txt | 1 + include/openssl/cmserr.h | 3 ++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 40f79eefa9..40aeb7088c 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 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 @@ -156,6 +156,8 @@ static const ERR_STRING_DATA CMS_str_reasons[] = { "unsupported recipientinfo type"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_RECIPIENT_TYPE), "unsupported recipient type"}, + {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM), + "unsupported signature algorithm"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_TYPE), "unsupported type"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNWRAP_ERROR), "unwrap error"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNWRAP_FAILURE), "unwrap failure"}, diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c index c32e95f10d..43a404da14 100644 --- a/crypto/cms/cms_sd.c +++ b/crypto/cms/cms_sd.c @@ -386,11 +386,15 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, if (md == NULL) { int def_nid; - if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) + if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) { + ERR_raise_data(ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST, + "pkey nid=%d", EVP_PKEY_get_id(pk)); goto err; + } md = EVP_get_digestbynid(def_nid); if (md == NULL) { - ERR_raise(ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST); + ERR_raise_data(ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST, + "default md nid=%d", def_nid); goto err; } } @@ -422,8 +426,11 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, } } - if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) + if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) { + ERR_raise_data(ERR_LIB_CMS, CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM, + "pkey nid=%d", EVP_PKEY_get_id(pk)); goto err; + } if (!(flags & CMS_NOATTR)) { /* * Initialize signed attributes structure so other attributes diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 6952560d86..1211b500c3 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -387,6 +387,7 @@ CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM:179:\ CMS_R_UNSUPPORTED_LABEL_SOURCE:193:unsupported label source CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE:155:unsupported recipientinfo type CMS_R_UNSUPPORTED_RECIPIENT_TYPE:154:unsupported recipient type +CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM:195:unsupported signature algorithm CMS_R_UNSUPPORTED_TYPE:156:unsupported type CMS_R_UNWRAP_ERROR:157:unwrap error CMS_R_UNWRAP_FAILURE:180:unwrap failure diff --git a/include/openssl/cmserr.h b/include/openssl/cmserr.h index 9066cab6a7..887035b1bf 100644 --- a/include/openssl/cmserr.h +++ b/include/openssl/cmserr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 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 @@ -114,6 +114,7 @@ # define CMS_R_UNSUPPORTED_LABEL_SOURCE 193 # define CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE 155 # define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154 +# define CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM 195 # define CMS_R_UNSUPPORTED_TYPE 156 # define CMS_R_UNWRAP_ERROR 157 # define CMS_R_UNWRAP_FAILURE 180 -- Gitee From 81a60733cb76599511d784d974c432b3d9202fb0 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 13 Oct 2023 22:27:31 +0200 Subject: [PATCH 05/67] EVP shake_ctrl(): add missing NULL evp_ctx check Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22390) Signed-off-by: fly2x --- crypto/evp/legacy_sha.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crypto/evp/legacy_sha.c b/crypto/evp/legacy_sha.c index 3859286eeb..0c2afc2900 100644 --- a/crypto/evp/legacy_sha.c +++ b/crypto/evp/legacy_sha.c @@ -71,7 +71,11 @@ static int sha1_int_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2) static int shake_ctrl(EVP_MD_CTX *evp_ctx, int cmd, int p1, void *p2) { - KECCAK1600_CTX *ctx = evp_ctx->md_data; + KECCAK1600_CTX *ctx; + + if (evp_ctx == NULL) + return 0; + ctx = evp_ctx->md_data; switch (cmd) { case EVP_MD_CTRL_XOF_LEN: -- Gitee From 973385b523a18667f0510abfc446ee9554f88eec Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 16 Oct 2023 14:42:12 +0900 Subject: [PATCH 06/67] rsa: Accept NULL OAEP label for backward compatibility According to the manual page, EVP_PKEY_CTX_set0_rsa_oaep_label() should accept NULL as the label argument, though the function currently rejects it while setting the corresponding octet string parameter with OSSL_PARAM_construct_octet_string, which expects non-NULL input. This adds a workaround to the caller for backward compatibility. Signed-off-by: Daiki Ueno Reviewed-by: Dmitry Belyavskiy Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22397) Signed-off-by: fly2x --- crypto/rsa/rsa_lib.c | 12 +++++++++++- test/evp_extra_test.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index f1be433512..db77a6fd49 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -1086,6 +1086,12 @@ int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, int llen) { OSSL_PARAM rsa_params[2], *p = rsa_params; + const char *empty = ""; + /* + * Needed as we swap label with empty if it is NULL, and label is + * freed at the end of this function. + */ + void *plabel = label; int ret; if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { @@ -1098,9 +1104,13 @@ int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, int llen) if (!EVP_PKEY_CTX_is_a(ctx, "RSA")) return -1; + /* Accept NULL for backward compatibility */ + if (label == NULL && llen == 0) + plabel = (void *)empty; + /* Cast away the const. This is read only so should be safe */ *p++ = OSSL_PARAM_construct_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, - (void *)label, (size_t)llen); + (void *)plabel, (size_t)llen); *p++ = OSSL_PARAM_construct_end(); ret = evp_pkey_ctx_set_params_strict(ctx, rsa_params); diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index a0724981de..6e61b8e925 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -3046,6 +3046,36 @@ static int test_RSA_OAEP_set_get_params(void) return ret; } +/* https://github.com/openssl/openssl/issues/21288 */ +static int test_RSA_OAEP_set_null_label(void) +{ + int ret = 0; + EVP_PKEY *key = NULL; + EVP_PKEY_CTX *key_ctx = NULL; + + if (!TEST_ptr(key = load_example_rsa_key()) + || !TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(testctx, key, NULL)) + || !TEST_true(EVP_PKEY_encrypt_init(key_ctx))) + goto err; + + if (!TEST_true(EVP_PKEY_CTX_set_rsa_padding(key_ctx, RSA_PKCS1_OAEP_PADDING))) + goto err; + + if (!TEST_true(EVP_PKEY_CTX_set0_rsa_oaep_label(key_ctx, OPENSSL_strdup("foo"), 0))) + goto err; + + if (!TEST_true(EVP_PKEY_CTX_set0_rsa_oaep_label(key_ctx, NULL, 0))) + goto err; + + ret = 1; + + err: + EVP_PKEY_free(key); + EVP_PKEY_CTX_free(key_ctx); + + return ret; +} + #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) static int test_decrypt_null_chunks(void) { @@ -5101,6 +5131,7 @@ int setup_tests(void) #endif ADD_TEST(test_RSA_get_set_params); ADD_TEST(test_RSA_OAEP_set_get_params); + ADD_TEST(test_RSA_OAEP_set_null_label); #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) ADD_TEST(test_decrypt_null_chunks); #endif -- Gitee From 00b1a7c21a97db39864fd5f2598b47a707b61b5e Mon Sep 17 00:00:00 2001 From: Pavel Stetsuk Date: Thu, 14 Sep 2023 23:05:49 +0300 Subject: [PATCH 07/67] fix: LINEAR search doesn't work properly (if CHARSET_EBCDIC is defined) CLA: trivial Reviewed-by: Paul Dale Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22108) Signed-off-by: fly2x --- crypto/objects/obj_dat.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c index 2c1a288167..209059aa7c 100644 --- a/crypto/objects/obj_dat.c +++ b/crypto/objects/obj_dat.c @@ -677,13 +677,14 @@ const void *OBJ_bsearch_ex_(const void *key, const void *base, int num, if (p == NULL) { const char *base_ = base; int l, h, i = 0, c = 0; + char *p1; for (i = 0; i < num; ++i) { - p = &(base_[i * size]); - c = (*cmp) (key, p); + p1 = &(base_[i * size]); + c = (*cmp) (key, p1); if (c == 0 || (c < 0 && (flags & OBJ_BSEARCH_VALUE_ON_NOMATCH))) - return p; + return p1; } } #endif -- Gitee From 18b6cca19460f54720396d8a5801964740c59a3f Mon Sep 17 00:00:00 2001 From: James Muir Date: Sat, 14 Oct 2023 19:36:57 -0400 Subject: [PATCH 08/67] cms encrypt, better OBJ_nid2obj() return check Fixes #22225 In OBJ_nid2obj(), if the NID does not have an OID, then a pointer to the special "undefined" ASN1_OBJECT is returned. Check for the undefined-ASN1_OBJECT and return an error. Also, add a test for this in 80-test_cms.t. Testing: #!/bin/bash -x shopt -s expand_aliases alias openssl="LD_LIBRARY_PATH=~/git/openssl ~/git/openssl/apps/openssl" echo "This is a confidential message. It should be encrypted." > msg.txt ## this should fail b/c there is no OID for aes-256-ctr openssl cms -encrypt -in msg.txt -aes-256-ctr -out msg.txt.cms -recip demos/cms/signer.pem echo $? Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22392) Signed-off-by: fly2x --- crypto/cms/cms_enc.c | 2 +- test/recipes/80-test_cms.t | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c index c9a5cfc69b..3f1328c041 100644 --- a/crypto/cms/cms_enc.c +++ b/crypto/cms/cms_enc.c @@ -81,7 +81,7 @@ BIO *ossl_cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec, if (enc) { calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx)); - if (calg->algorithm == NULL) { + if (calg->algorithm == NULL || calg->algorithm->nid == NID_undef) { ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM); goto err; } diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index 3857916105..0e1ebc50cd 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -50,7 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib) $no_rc2 = 1 if disabled("legacy"); -plan tests => 21; +plan tests => 22; ok(run(test(["pkcs7_test"])), "test pkcs7"); @@ -1154,3 +1154,14 @@ with({ exit_checker => sub { return shift == 3; } }, "issue#21986"); } }); + +# Test for problem reported in #22225 +with({ exit_checker => sub { return shift == 3; } }, + sub { + ok(run(app(['openssl', 'cms', '-encrypt', + '-in', srctop_file("test", "smcont.txt"), + '-aes-256-ctr', '-recip', + catfile($smdir, "smec1.pem"), + ])), + "Check for failure when cipher does not have an assigned OID (issue#22225)"); + }); -- Gitee From 856b3651735cc2d1e45671f4b430ffc01d413890 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 11 Oct 2023 09:34:02 -0400 Subject: [PATCH 09/67] ensure that ossl_obj_nid_lock is allocated before use external calls to OBJ_new_nid will fail on an attempt to lock the ossl_obj_nid_lock as it won't have been initalized yet. Bifurcate OBJ_new_nid into an external and internal variant, in which the former calls ossl_obj_write_lock (ensuring that the nid_lock is initalized), while OBJ_create (the sole internal caller) uses the latter to avoid having to drop and re-acquire the lock Fixes #22337 Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22350) Signed-off-by: fly2x --- crypto/objects/obj_dat.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c index 209059aa7c..b0e1032ec2 100644 --- a/crypto/objects/obj_dat.c +++ b/crypto/objects/obj_dat.c @@ -221,25 +221,45 @@ void ossl_obj_cleanup_int(void) objs_free_locks(); } -int OBJ_new_nid(int num) +/* + * Requires that the ossl_obj_lock be held + * if TSAN_REQUIRES_LOCKING defined + */ +static int obj_new_nid_unlocked(int num) { static TSAN_QUALIFIER int new_nid = NUM_NID; #ifdef TSAN_REQUIRES_LOCKING int i; - if (!CRYPTO_THREAD_write_lock(ossl_obj_nid_lock)) { - ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_WRITE_LOCK); - return NID_undef; - } i = new_nid; new_nid += num; - CRYPTO_THREAD_unlock(ossl_obj_nid_lock); + return i; #else return tsan_add(&new_nid, num); #endif } +int OBJ_new_nid(int num) +{ +#ifdef TSAN_REQUIRES_LOCKING + int i; + + if (!ossl_obj_write_lock(1)) { + ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_WRITE_LOCK); + return NID_undef; + } + + i = obj_new_nid_unlocked(num); + + ossl_obj_unlock(1); + + return i; +#else + return obj_new_nid_unlocked(num); +#endif +} + static int ossl_obj_add_object(const ASN1_OBJECT *obj, int lock) { ASN1_OBJECT *o = NULL; @@ -785,7 +805,8 @@ int OBJ_create(const char *oid, const char *sn, const char *ln) goto err; } - tmpoid->nid = OBJ_new_nid(1); + tmpoid->nid = obj_new_nid_unlocked(1); + if (tmpoid->nid == NID_undef) goto err; -- Gitee From 934af6b5d35198ddfc88e3fa8c10d6d8fdc3c11e Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 4 Sep 2023 11:10:42 +0200 Subject: [PATCH 10/67] ossl_param_build_set_multi_key_bn(): Do not set NULL BIGNUMs This makes them zeroes otherwise where NULLs actually mean the values aren't present. Fixes #21935 Reviewed-by: Richard Levitte Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/22334) Signed-off-by: fly2x --- crypto/param_build_set.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crypto/param_build_set.c b/crypto/param_build_set.c index e26ce15500..f205d10193 100644 --- a/crypto/param_build_set.c +++ b/crypto/param_build_set.c @@ -101,21 +101,22 @@ int ossl_param_build_set_multi_key_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *params, { int i, sz = sk_BIGNUM_const_num(stk); OSSL_PARAM *p; - + const BIGNUM *bn; if (bld != NULL) { for (i = 0; i < sz && names[i] != NULL; ++i) { - if (!OSSL_PARAM_BLD_push_BN(bld, names[i], - sk_BIGNUM_const_value(stk, i))) + bn = sk_BIGNUM_const_value(stk, i); + if (bn != NULL && !OSSL_PARAM_BLD_push_BN(bld, names[i], bn)) return 0; } return 1; } for (i = 0; i < sz && names[i] != NULL; ++i) { + bn = sk_BIGNUM_const_value(stk, i); p = OSSL_PARAM_locate(params, names[i]); - if (p != NULL) { - if (!OSSL_PARAM_set_BN(p, sk_BIGNUM_const_value(stk, i))) + if (p != NULL && bn != NULL) { + if (!OSSL_PARAM_set_BN(p, bn)) return 0; } } -- Gitee From 406771542a184723fb82afd95cb670c9090c431e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 5 Sep 2023 12:08:19 -0400 Subject: [PATCH 11/67] remove sanity check from ossl_rsa_todata Theres no reason we should gate ossl_rsa_todata on there being a minimum set of parameters. EVP_PKEY_todata makes no guarantees about the validity of a key, it only returns the parameters that are set in the requested key, whatever they may be. Remove the check. Fixes #21935 Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22334) Signed-off-by: fly2x --- crypto/rsa/rsa_backend.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c index c416d4bf61..7b2efa8862 100644 --- a/crypto/rsa/rsa_backend.c +++ b/crypto/rsa/rsa_backend.c @@ -141,18 +141,6 @@ int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[], /* Check private key data integrity */ if (include_private && rsa_d != NULL) { - int numprimes = sk_BIGNUM_const_num(factors); - int numexps = sk_BIGNUM_const_num(exps); - int numcoeffs = sk_BIGNUM_const_num(coeffs); - - /* - * It's permissible to have zero primes, i.e. no CRT params. - * Otherwise, there must be at least two, as many exponents, - * and one coefficient less. - */ - if (numprimes != 0 - && (numprimes < 2 || numexps < 2 || numcoeffs < 1)) - goto err; if (!ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_RSA_D, rsa_d) -- Gitee From 377364be0e95997b63577c168174c52239606b9e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 10 Oct 2023 11:06:44 -0400 Subject: [PATCH 12/67] Dont require CRT params on ossl_rsa_set0_all_params Its not required that crt params be available in an RSA key, so don't perform an error check on them Fixes #29135 Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22334) Signed-off-by: fly2x --- crypto/rsa/rsa_lib.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index db77a6fd49..9548054da7 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -757,18 +757,22 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, return 0; pnum = sk_BIGNUM_num(primes); - if (pnum < 2 - || pnum != sk_BIGNUM_num(exps) - || pnum != sk_BIGNUM_num(coeffs) + 1) + if (pnum < 2) return 0; if (!RSA_set0_factors(r, sk_BIGNUM_value(primes, 0), - sk_BIGNUM_value(primes, 1)) - || !RSA_set0_crt_params(r, sk_BIGNUM_value(exps, 0), - sk_BIGNUM_value(exps, 1), - sk_BIGNUM_value(coeffs, 0))) + sk_BIGNUM_value(primes, 1))) return 0; + if (pnum == sk_BIGNUM_num(exps) + && pnum == sk_BIGNUM_num(coeffs) + 1) { + + if (!RSA_set0_crt_params(r, sk_BIGNUM_value(exps, 0), + sk_BIGNUM_value(exps, 1), + sk_BIGNUM_value(coeffs, 0))) + return 0; + } + #ifndef FIPS_MODULE old_infos = r->prime_infos; #endif -- Gitee From a66aedf6b1b197797434c1d804ebaabb5cade093 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 11 Oct 2023 12:45:44 -0400 Subject: [PATCH 13/67] Add a test to confirm that legacy rsa keys work Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22334) Signed-off-by: fly2x --- test/rsa_test.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/test/rsa_test.c b/test/rsa_test.c index fe2087465f..88c2f6d25d 100644 --- a/test/rsa_test.c +++ b/test/rsa_test.c @@ -391,6 +391,121 @@ err: return r; } +static int test_EVP_rsa_legacy_key(void) +{ + int ret; + size_t buflen = 384; + size_t msglen = 64; + unsigned char sigbuf[384]; + unsigned char msgbuf[64]; + BIGNUM *p; + BIGNUM *q; + BIGNUM *n; + BIGNUM *d; + BIGNUM *e; + RSA *rsa; + const EVP_MD *md; + EVP_MD_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + + unsigned char n_data[] = { + 0x00, 0xc7, 0x28, 0x7a, 0x28, 0x91, 0x51, 0xa5, 0xe8, 0x3c, 0x45, 0xcf, + 0x1d, 0xa9, 0x69, 0x7a, 0x0d, 0xdb, 0xdd, 0x8f, 0xe2, 0xde, 0x85, 0xdd, + 0x85, 0x6d, 0x8f, 0x78, 0x20, 0xd6, 0xe, 0xe5, 0x06, 0xcb, 0x9c, 0xd6, + 0xd3, 0xca, 0xef, 0x1d, 0x80, 0xd3, 0x18, 0x23, 0x91, 0x5c, 0xe5, 0xc8, + 0x44, 0x37, 0x56, 0x1b, 0x68, 0x7f, 0x08, 0xa3, 0x1c, 0xf6, 0xe8, 0x11, + 0x38, 0x0f, 0x2e, 0xad, 0xb1, 0x89, 0x8b, 0x08, 0xe8, 0x35, 0xaf, 0x3b, + 0xfe, 0x37, 0x8d, 0x21, 0xd5, 0x3f, 0x1f, 0x4b, 0x01, 0x30, 0xd8, 0xd0, + 0x24, 0xf7, 0xab, 0x57, 0xad, 0xac, 0xbc, 0x53, 0x6d, 0x84, 0x8e, 0xa1, + 0xb2, 0x5b, 0x8e, 0xe7, 0xb3, 0xac, 0xfc, 0x60, 0x22, 0x10, 0x1e, 0x99, + 0xfa, 0xa0, 0x60, 0x00, 0x69, 0x5f, 0x8e, 0xca, 0x6d, 0x9c, 0xee, 0x5e, + 0x84, 0x4e, 0x53, 0x83, 0x42, 0x76, 0x4d, 0xb8, 0xc1, 0xeb, 0x4e, 0x3d, + 0xc3, 0xce, 0xac, 0x79, 0xbb, 0x29, 0x5d, 0x92, 0x33, 0x6e, 0xcf, 0x8f, + 0x5a, 0xf0, 0xb3, 0xb5, 0xdc, 0xd5, 0xa3, 0xaf, 0x40, 0x4b, 0x0f, 0x05, + 0xac, 0x46, 0x53, 0x2d, 0x5f, 0x20, 0x96, 0x42, 0xa8, 0x47, 0x61, 0x54, + 0x05, 0x2c, 0x8a, 0x26, 0x5d, 0x92, 0x1d, 0x01, 0x2a, 0x27, 0x8a, 0xfc, + 0x64, 0x24, 0x5c, 0x34, 0xde, 0x92, 0xc6, 0x82, 0xea, 0x4d, 0xe2, 0x52, + 0xe5, 0xad, 0x62, 0x00, 0xc6, 0xc8, 0xe9, 0x0c, 0x22, 0xf0, 0x9e, 0xbe, + 0xdc, 0x51, 0x58, 0xad, 0x3b, 0xba, 0x2e, 0x45, 0x65, 0xcc, 0x5b, 0x55, + 0x46, 0x67, 0x18, 0x4a, 0x80, 0x67, 0x5b, 0x84, 0x7f, 0x13, 0x37, 0x45, + 0xd8, 0x03, 0xc6, 0x22, 0xc3, 0x4a, 0x46, 0x6b, 0xde, 0x50, 0xbf, 0x16, + 0x0a, 0x23, 0x0b, 0xaa, 0x50, 0x54, 0xf6, 0x20, 0x83, 0x74, 0x33, 0x97, + 0x2e, 0xf2, 0x8e, 0x7e, 0x13 }; + + unsigned char e_data[] = { 0x01, 0x00, 0x01 }; + + unsigned char d_data[] = { + 0x09, 0x2d, 0xcb, 0xe7, 0x87, 0xbf, 0x10, 0x1a, 0xf2, 0x80, 0x33, 0x2a, + 0x06, 0x4f, 0x56, 0xb1, 0x41, 0xd3, 0x65, 0xd8, 0xca, 0x71, 0xb8, 0x02, + 0x78, 0xc8, 0xb6, 0x7c, 0x28, 0xf4, 0x6c, 0xe8, 0xd1, 0xc4, 0x92, 0x40, + 0x23, 0xa7, 0xbe, 0x9f, 0xdb, 0xda, 0xce, 0x74, 0xda, 0x27, 0xbb, 0x01, + 0xad, 0xdd, 0x39, 0x99, 0x28, 0xd5, 0xb0, 0x92, 0xda, 0xac, 0x5a, 0x72, + 0xcf, 0x7c, 0x52, 0xc4, 0x0e, 0x77, 0x4a, 0x7b, 0x4d, 0x52, 0x1c, 0xbd, + 0x3c, 0x39, 0x34, 0x78, 0x7c, 0x16, 0xc8, 0xa1, 0xae, 0xeb, 0x27, 0x38, + 0xb4, 0xf3, 0x80, 0x30, 0x80, 0x78, 0x13, 0x8e, 0x46, 0x20, 0x3e, 0xc2, + 0x96, 0x26, 0xb1, 0x76, 0x1e, 0x00, 0x69, 0xbb, 0xd8, 0x2b, 0x58, 0xe4, + 0x6c, 0xb4, 0xd0, 0x00, 0x0b, 0x47, 0xec, 0xfb, 0x7d, 0x52, 0x9d, 0x27, + 0x92, 0xe6, 0x95, 0x73, 0xa0, 0x39, 0x37, 0xcd, 0x1f, 0x60, 0x13, 0x1c, + 0x87, 0x9d, 0xa7, 0x91, 0x90, 0xf9, 0x36, 0xc5, 0xfa, 0x3f, 0xf9, 0x7f, + 0x50, 0xf8, 0xb3, 0x54, 0x65, 0xff, 0x6f, 0xa6, 0x22, 0xcc, 0x4a, 0x1e, + 0x49, 0x3f, 0x07, 0xc6, 0xf2, 0x65, 0x73, 0x13, 0x1b, 0x2d, 0xb6, 0x15, + 0xff, 0xcd, 0x9a, 0x1c, 0xea, 0xef, 0x58, 0x56, 0x91, 0x2d, 0x47, 0x81, + 0x56, 0x0d, 0xc3, 0xb0, 0x47, 0x58, 0x8d, 0x05, 0x7d, 0x5b, 0xc0, 0x22, + 0xa4, 0xf0, 0x2e, 0x70, 0x36, 0x01, 0x89, 0xa1, 0x71, 0xed, 0x76, 0xe9, + 0x8d, 0xf5, 0x49, 0xaf, 0x11, 0xbe, 0xe4, 0xd4, 0x48, 0x92, 0xb6, 0x5b, + 0xc2, 0x04, 0xd4, 0x0c, 0x5c, 0x8b, 0xe3, 0xfa, 0x29, 0x63, 0x86, 0xb4, + 0x10, 0xad, 0x32, 0x07, 0x85, 0xe2, 0x43, 0x76, 0x16, 0x90, 0xab, 0xdf, + 0xb3, 0x36, 0x0a, 0xc4, 0x49, 0x7b, 0x95, 0x48, 0x50, 0x72, 0x8f, 0x7d, + 0xf4, 0xfa, 0x60, 0xc1 }; + + unsigned char p_data[] = { + 0x00, 0xed, 0xf7, 0xa7, 0x00, 0x5a, 0xbb, 0xd1, 0x52, 0x65, 0x9b, 0xec, + 0xfe, 0x27, 0x8b, 0xe2, 0xbe, 0x40, 0x8c, 0x2f, 0x6f, 0xb4, 0x26, 0xb2, + 0xbe, 0x45, 0x4b, 0x3b, 0x5a, 0xaa, 0xc6, 0xaa, 0xfa, 0xc1, 0x3a, 0xa9, + 0xa1, 0xba, 0xb7, 0x86, 0x1a, 0x98, 0x15, 0x5f, 0x5c, 0x1c, 0x57, 0x78, + 0x78, 0x6a, 0x13, 0xc2, 0x40, 0x7d, 0x07, 0x87, 0x47, 0xc6, 0x96, 0xd5, + 0x92, 0xc9, 0x65, 0x2c, 0xfe, 0xbb, 0xe0, 0xd6, 0x76, 0x25, 0x5a, 0xa3, + 0xdf, 0x97, 0x4b, 0x64, 0xfd, 0x3b, 0x2b, 0xbc, 0xfb, 0x80, 0xad, 0x3b, + 0x7d, 0x1f, 0x48, 0x56, 0x27, 0xf7, 0x2f, 0x8e, 0x92, 0x07, 0xa8, 0x9f, + 0xbc, 0x5a, 0xce, 0xfa, 0xd5, 0x67, 0xad, 0xf4, 0xbf, 0xe0, 0xc9, 0x3e, + 0x8e, 0xb5, 0x90, 0x58, 0x54, 0x92, 0x9f, 0xda, 0x36, 0xc0, 0x0d, 0x57, + 0xfe, 0x6c, 0x23, 0x63, 0x8b, 0xd1, 0x1e, 0x4f, 0xd3 }; + + unsigned char q_data[] = { + 0x00, 0xd6, 0x3f, 0xf5, 0xee, 0xff, 0x4d, 0x7d, 0x8c, 0x1a, 0x85, 0x5d, + 0x3c, 0x4f, 0x9d, 0xdf, 0xc7, 0x68, 0x27, 0x7f, 0xe4, 0x4f, 0x4f, 0xd7, + 0xa2, 0x3b, 0xcd, 0x4a, 0x34, 0xd8, 0x55, 0x4a, 0x3e, 0x8e, 0xb3, 0xa8, + 0xe9, 0x8a, 0xc5, 0x94, 0xd1, 0x09, 0x32, 0x4b, 0x79, 0x8d, 0x7b, 0x03, + 0x0b, 0x5d, 0xca, 0x91, 0x41, 0xbc, 0x82, 0xc3, 0x89, 0x67, 0x4d, 0x03, + 0x68, 0x03, 0x2d, 0x0e, 0x4e, 0x97, 0x6c, 0xf6, 0x3e, 0x1f, 0xf4, 0x50, + 0x06, 0x5d, 0x05, 0x22, 0xf2, 0xf8, 0xf2, 0xde, 0xad, 0x2e, 0x9d, 0xc3, + 0x97, 0x1b, 0xc3, 0x75, 0xe7, 0x86, 0xde, 0xc5, 0x11, 0x89, 0xed, 0x6a, + 0x13, 0x14, 0x23, 0x4b, 0x98, 0x81, 0xf7, 0xd4, 0x1c, 0xee, 0x30, 0x92, + 0x85, 0x20, 0x4f, 0x35, 0x02, 0xfa, 0xda, 0x14, 0x77, 0xfa, 0x08, 0x34, + 0x60, 0xc7, 0x93, 0x72, 0xdc, 0xc4, 0x18, 0x70, 0xc1 }; + + memset(msgbuf, 0xdeadbeef, 64); + + ret = (TEST_ptr((p = BN_bin2bn(p_data, sizeof(p_data), NULL))) + && TEST_ptr((q = BN_bin2bn(q_data, sizeof(q_data), NULL))) + && TEST_ptr((n = BN_bin2bn(n_data, sizeof(n_data), NULL))) + && TEST_ptr((d = BN_bin2bn(d_data, sizeof(d_data), NULL))) + && TEST_ptr((e = BN_bin2bn(e_data, sizeof(e_data), NULL))) + && TEST_ptr((rsa = RSA_new())) + && TEST_ptr((md = EVP_sha256())) + && TEST_ptr((ctx = EVP_MD_CTX_new())) + && TEST_ptr((pkey = EVP_PKEY_new())) + && TEST_true(RSA_set0_factors(rsa, p, q)) + && TEST_true(RSA_set0_key(rsa, n, e, d)) + && TEST_true(EVP_PKEY_assign_RSA(pkey, rsa)) + && TEST_true(EVP_DigestSignInit(ctx, NULL, md, NULL, pkey)) + && TEST_true(EVP_DigestSign(ctx, sigbuf, &buflen, msgbuf, msglen))); + + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + return ret; +} + static RSA *load_key(int priv) { RSA *rsa = NULL; @@ -600,5 +715,6 @@ int setup_tests(void) ADD_ALL_TESTS(test_rsa_oaep, 3); ADD_ALL_TESTS(test_rsa_security_bit, OSSL_NELEM(rsa_security_bits_cases)); ADD_TEST(test_rsa_saos); + ADD_TEST(test_EVP_rsa_legacy_key); return 1; } -- Gitee From 67d909ba6e4ba4b29ea64534c6b71ca739f6f86f Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 13:33:11 +0100 Subject: [PATCH 14/67] QUIC: Add HTTP/3 demo using nghttp3 Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/Makefile | 14 + demos/http3/ossl-nghttp3-demo.c | 142 ++++++++ demos/http3/ossl-nghttp3.c | 603 ++++++++++++++++++++++++++++++++ demos/http3/ossl-nghttp3.h | 96 +++++ 4 files changed, 855 insertions(+) create mode 100644 demos/http3/Makefile create mode 100644 demos/http3/ossl-nghttp3-demo.c create mode 100644 demos/http3/ossl-nghttp3.c create mode 100644 demos/http3/ossl-nghttp3.h diff --git a/demos/http3/Makefile b/demos/http3/Makefile new file mode 100644 index 0000000000..89bac3743e --- /dev/null +++ b/demos/http3/Makefile @@ -0,0 +1,14 @@ +CFLAGS = -I../../include -g -Wall +LDFLAGS = -L../.. +LDLIBS = -lcrypto -lssl -lnghttp3 + +all: ossl-nghttp3-demo + +clean: + $(RM) -f ossl-nghttp3-demo *.o + +ossl-nghttp3-demo: ossl-nghttp3-demo.o ossl-nghttp3.o + $(CC) $(CFLAGS) -o "$@" $^ $(LDFLAGS) $(LDLIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o "$@" "$<" diff --git a/demos/http3/ossl-nghttp3-demo.c b/demos/http3/ossl-nghttp3-demo.c new file mode 100644 index 0000000000..53acf31e40 --- /dev/null +++ b/demos/http3/ossl-nghttp3-demo.c @@ -0,0 +1,142 @@ +#include "ossl-nghttp3.h" +#include + +static int done; + +static void make_nv(nghttp3_nv *nv, const char *name, const char *value) +{ + nv->name = (uint8_t *)name; + nv->value = (uint8_t *)value; + nv->namelen = strlen(name); + nv->valuelen = strlen(value); + nv->flags = NGHTTP3_NV_FLAG_NONE; +} + +static int on_recv_header(nghttp3_conn *h3conn, int64_t stream_id, + int32_t token, + nghttp3_rcbuf *name, nghttp3_rcbuf *value, + uint8_t flags, + void *conn_user_data, + void *stream_user_data) +{ + nghttp3_vec vname, vvalue; + + /* Received a single HTTP header. */ + vname = nghttp3_rcbuf_get_buf(name); + vvalue = nghttp3_rcbuf_get_buf(value); + + fwrite(vname.base, vname.len, 1, stderr); + fprintf(stderr, ": "); + fwrite(vvalue.base, vvalue.len, 1, stderr); + fprintf(stderr, "\n"); + + return 0; +} + +static int on_end_headers(nghttp3_conn *h3conn, int64_t stream_id, + int fin, + void *conn_user_data, void *stream_user_data) +{ + fprintf(stderr, "\n"); + return 0; +} + +static int on_recv_data(nghttp3_conn *h3conn, int64_t stream_id, + const uint8_t *data, size_t datalen, + void *conn_user_data, void *stream_user_data) +{ + ssize_t wr; + + /* HTTP response body data - write it to stdout. */ + while (datalen > 0) { + wr = fwrite(data, 1, datalen, stdout); + if (wr < 0) + return 1; + + data += wr; + datalen -= wr; + } + + return 0; +} + +static int on_end_stream(nghttp3_conn *h3conn, int64_t stream_id, + void *conn_user_data, void *stream_user_data) +{ + /* HTTP transaction is done - set done flag so that we stop looping. */ + done = 1; + return 0; +} + +int main(int argc, char **argv) +{ + int ret = 1; + SSL_CTX *ctx = NULL; + H3_CONN *conn = NULL; + nghttp3_nv nva[16]; + nghttp3_callbacks callbacks = {0}; + size_t num_nv = 0; + const char *addr; + + /* Check arguments. */ + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + goto err; + } + + addr = argv[1]; + + /* Setup SSL_CTX. */ + if ((ctx = SSL_CTX_new(OSSL_QUIC_client_method())) == NULL) + goto err; + + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + + if (SSL_CTX_set_default_verify_paths(ctx) == 0) + goto err; + + /* Setup callbacks. */ + callbacks.recv_header = on_recv_header; + callbacks.end_headers = on_end_headers; + callbacks.recv_data = on_recv_data; + callbacks.end_stream = on_end_stream; + + /* Create connection. */ + if ((conn = H3_CONN_new_for_addr(ctx, addr, &callbacks, + NULL, NULL)) == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, + "cannot create HTTP/3 connection"); + goto err; + } + + /* Build HTTP headers. */ + make_nv(&nva[num_nv++], ":method", "GET"); + make_nv(&nva[num_nv++], ":scheme", "https"); + make_nv(&nva[num_nv++], ":authority", addr); + make_nv(&nva[num_nv++], ":path", "/"); + make_nv(&nva[num_nv++], "user-agent", "OpenSSL-Demo/nghttp3"); + + /* Submit request. */ + if (!H3_CONN_submit_request(conn, nva, num_nv, NULL, NULL)) { + ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, + "cannot submit HTTP/3 request"); + goto err; + } + + /* Wait for request to complete. */ + while (!done) + if (!H3_CONN_handle_events(conn)) { + ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, + "cannot handle events"); + goto err; + } + + ret = 0; +err: + if (ret != 0) + ERR_print_errors_fp(stderr); + + H3_CONN_free(conn); + SSL_CTX_free(ctx); + return ret; +} diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c new file mode 100644 index 0000000000..97bf8baec3 --- /dev/null +++ b/demos/http3/ossl-nghttp3.c @@ -0,0 +1,603 @@ +#include "ossl-nghttp3.h" +#include +#include + +#define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0])) + +enum { + H3_STREAM_TYPE_CTRL_SEND, + H3_STREAM_TYPE_QPACK_ENC_SEND, + H3_STREAM_TYPE_QPACK_DEC_SEND, + H3_STREAM_TYPE_REQ, +}; + +#define BUF_SIZE 4096 + +struct h3_stream_st { + uint64_t id; /* QUIC stream ID */ + SSL *s; /* QUIC stream SSL object */ + int done_recv_fin; /* Received FIN */ + void *user_data; + + uint8_t buf[BUF_SIZE]; + size_t buf_cur, buf_total; +}; + +DEFINE_LHASH_OF_EX(H3_STREAM); + +static void h3_stream_free(H3_STREAM *s) +{ + if (s == NULL) + return; + + SSL_free(s->s); + OPENSSL_free(s); +} + +static unsigned long h3_stream_hash(const H3_STREAM *s) +{ + return (unsigned long)s->id; +} + +static int h3_stream_eq(const H3_STREAM *a, const H3_STREAM *b) +{ + if (a->id < b->id) return -1; + if (a->id > b->id) return 1; + return 0; +} + +void *H3_STREAM_get_user_data(const H3_STREAM *s) +{ + return s->user_data; +} + +struct h3_conn_st { + SSL *qconn; /* QUIC connection SSL object */ + BIO *qconn_bio; /* BIO wrapping QCSO */ + nghttp3_conn *h3conn; /* HTTP/3 connection object */ + LHASH_OF(H3_STREAM) *streams; /* map of stream IDs to H3_STREAMs */ + void *user_data; /* opaque user data pointer */ + + int pump_res; + size_t consumed_app_data; + + /* Forwarding callbacks */ + nghttp3_recv_data recv_data_cb; + nghttp3_stream_close stream_close_cb; + nghttp3_stop_sending stop_sending_cb; + nghttp3_reset_stream reset_stream_cb; + nghttp3_deferred_consume deferred_consume_cb; +}; + +void H3_CONN_free(H3_CONN *conn) +{ + if (conn == NULL) + return; + + lh_H3_STREAM_doall(conn->streams, h3_stream_free); + + nghttp3_conn_del(conn->h3conn); + BIO_free_all(conn->qconn_bio); + lh_H3_STREAM_free(conn->streams); + OPENSSL_free(conn); +} + +static H3_STREAM *h3_conn_create_stream(H3_CONN *conn, int type) +{ + H3_STREAM *s; + uint64_t flags = SSL_STREAM_FLAG_ADVANCE; + + if ((s = OPENSSL_zalloc(sizeof(H3_STREAM))) == NULL) + return NULL; + + if (type != H3_STREAM_TYPE_REQ) + flags |= SSL_STREAM_FLAG_UNI; + + if ((s->s = SSL_new_stream(conn->qconn, flags)) == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "could not create QUIC stream object"); + goto err; + } + + s->id = SSL_get_stream_id(s->s); + lh_H3_STREAM_insert(conn->streams, s); + return s; + +err: + OPENSSL_free(s); + return NULL; +} + +static H3_STREAM *h3_conn_accept_stream(H3_CONN *conn, SSL *qstream) +{ + H3_STREAM *s; + + if ((s = OPENSSL_zalloc(sizeof(H3_STREAM))) == NULL) + return NULL; + + s->id = SSL_get_stream_id(qstream); + s->s = qstream; + lh_H3_STREAM_insert(conn->streams, s); + return s; +} + +static void h3_conn_remove_stream(H3_CONN *conn, H3_STREAM *s) +{ + if (s == NULL) + return; + + lh_H3_STREAM_delete(conn->streams, s); + h3_stream_free(s); +} + +static int h3_conn_recv_data(nghttp3_conn *h3conn, int64_t stream_id, + const uint8_t *data, size_t datalen, + void *conn_user_data, void *stream_user_data) +{ + H3_CONN *conn = conn_user_data; + + conn->consumed_app_data += datalen; + if (conn->recv_data_cb == NULL) + return 0; + + return conn->recv_data_cb(h3conn, stream_id, data, datalen, + conn_user_data, stream_user_data); +} + +static int h3_conn_stream_close(nghttp3_conn *h3conn, int64_t stream_id, + uint64_t app_error_code, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + H3_CONN *conn = conn_user_data; + H3_STREAM *stream = stream_user_data; + + if (conn->stream_close_cb != NULL) + ret = conn->stream_close_cb(h3conn, stream_id, app_error_code, + conn_user_data, stream_user_data); + + h3_conn_remove_stream(conn, stream); + return ret; +} + +static int h3_conn_stop_sending(nghttp3_conn *h3conn, int64_t stream_id, + uint64_t app_error_code, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + H3_CONN *conn = conn_user_data; + H3_STREAM *stream = stream_user_data; + + if (conn->stop_sending_cb != NULL) + ret = conn->stop_sending_cb(h3conn, stream_id, app_error_code, + conn_user_data, stream_user_data); + + SSL_free(stream->s); + stream->s = NULL; + return ret; +} + +static int h3_conn_reset_stream(nghttp3_conn *h3conn, int64_t stream_id, + uint64_t app_error_code, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + H3_CONN *conn = conn_user_data; + H3_STREAM *stream = stream_user_data; + SSL_STREAM_RESET_ARGS args = {0}; + + if (conn->reset_stream_cb != NULL) + ret = conn->reset_stream_cb(h3conn, stream_id, app_error_code, + conn_user_data, stream_user_data); + + if (stream->s != NULL) { + args.quic_error_code = app_error_code; + + if (!SSL_stream_reset(stream->s, &args, sizeof(args))) + return 1; + } + + return ret; +} + +static int h3_conn_deferred_consume(nghttp3_conn *h3conn, int64_t stream_id, + size_t consumed, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + H3_CONN *conn = conn_user_data; + + if (conn->deferred_consume_cb != NULL) + ret = conn->deferred_consume_cb(h3conn, stream_id, consumed, + conn_user_data, stream_user_data); + + conn->consumed_app_data += consumed; + return ret; +} + +H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data) +{ + int ec; + H3_CONN *conn; + H3_STREAM *s_ctl_send = NULL, *s_qpenc_send = NULL, *s_qpdec_send = NULL; + nghttp3_settings dsettings = {0}; + nghttp3_callbacks intl_callbacks = {0}; + static const unsigned char alpn[] = {2, 'h', '3'}; + + if (qconn_bio == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER, + "QUIC connection BIO must be provided"); + return NULL; + } + + if ((conn = OPENSSL_zalloc(sizeof(H3_CONN))) == NULL) + return NULL; + + conn->qconn_bio = qconn_bio; + conn->user_data = user_data; + + if (BIO_get_ssl(qconn_bio, &conn->qconn) == 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_INVALID_ARGUMENT, + "BIO must be an SSL BIO"); + goto err; + } + + if ((conn->streams = lh_H3_STREAM_new(h3_stream_hash, h3_stream_eq)) == NULL) + goto err; + + if (SSL_in_before(conn->qconn)) + if (SSL_set_alpn_protos(conn->qconn, alpn, sizeof(alpn))) { + /* SSL_set_alpn_protos returns 1 on failure */ + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "failed to configure ALPN"); + goto err; + } + + BIO_set_nbio(conn->qconn_bio, 1); + + if (!SSL_set_default_stream_mode(conn->qconn, SSL_DEFAULT_STREAM_MODE_NONE)) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "failed to configure default stream mode"); + goto err; + } + + if ((s_ctl_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_CTRL_SEND)) == NULL) + goto err; + + if ((s_qpenc_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_QPACK_ENC_SEND)) == NULL) + goto err; + + if ((s_qpdec_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_QPACK_DEC_SEND)) == NULL) + goto err; + + if (settings == NULL) { + nghttp3_settings_default(&dsettings); + settings = &dsettings; + } + + if (callbacks != NULL) + intl_callbacks = *callbacks; + + conn->recv_data_cb = intl_callbacks.recv_data; + conn->stream_close_cb = intl_callbacks.stream_close; + conn->stop_sending_cb = intl_callbacks.stop_sending; + conn->reset_stream_cb = intl_callbacks.reset_stream; + conn->deferred_consume_cb = intl_callbacks.deferred_consume; + + intl_callbacks.recv_data = h3_conn_recv_data; + intl_callbacks.stream_close = h3_conn_stream_close; + intl_callbacks.stop_sending = h3_conn_stop_sending; + intl_callbacks.reset_stream = h3_conn_reset_stream; + intl_callbacks.deferred_consume = h3_conn_deferred_consume; + + ec = nghttp3_conn_client_new(&conn->h3conn, &intl_callbacks, settings, + NULL, conn); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot create nghttp3 connection: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + ec = nghttp3_conn_bind_control_stream(conn->h3conn, s_ctl_send->id); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot bind nghttp3 control stream: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + ec = nghttp3_conn_bind_qpack_streams(conn->h3conn, + s_qpenc_send->id, + s_qpdec_send->id); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot bind nghttp3 QPACK streams: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + return conn; + +err: + nghttp3_conn_del(conn->h3conn); + h3_stream_free(s_ctl_send); + h3_stream_free(s_qpenc_send); + h3_stream_free(s_qpdec_send); + lh_H3_STREAM_free(conn->streams); + OPENSSL_free(conn); + return NULL; +} + +H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data) +{ + BIO *qconn_bio = NULL; + SSL *qconn = NULL; + H3_CONN *conn = NULL; + const char *bare_hostname; + + /* QUIC connection setup */ + if ((qconn_bio = BIO_new_ssl_connect(ctx)) == NULL) + goto err; + + if (BIO_set_conn_hostname(qconn_bio, addr) == 0) + goto err; + + bare_hostname = BIO_get_conn_hostname(qconn_bio); + if (bare_hostname == NULL) + goto err; + + if (BIO_get_ssl(qconn_bio, &qconn) == 0) + goto err; + + if (SSL_set1_host(qconn, bare_hostname) <= 0) + goto err; + + conn = H3_CONN_new_for_conn(qconn_bio, callbacks, settings, user_data); + if (conn == NULL) + goto err; + + return conn; + +err: + BIO_free_all(qconn_bio); + return NULL; +} + +int H3_CONN_connect(H3_CONN *conn) +{ + return SSL_connect(H3_CONN_get0_connection(conn)); +} + +void *H3_CONN_get_user_data(const H3_CONN *conn) +{ + return conn->user_data; +} + +SSL *H3_CONN_get0_connection(const H3_CONN *conn) +{ + return conn->qconn; +} + +/* Pumps received data to the HTTP/3 stack for a single stream. */ +static void h3_conn_pump_stream(H3_STREAM *s, void *conn_) +{ + int ec; + H3_CONN *conn = conn_; + size_t num_bytes, consumed; + uint64_t aec; + + if (!conn->pump_res) + return; + + for (;;) { + if (s->s == NULL + || SSL_get_stream_read_state(s->s) == SSL_STREAM_STATE_WRONG_DIR + || s->done_recv_fin) + break; + + /* + * Pump data from OpenSSL QUIC to the HTTP/3 stack by calling SSL_peek + * to get received data and passing it to nghttp3 using + * nghttp3_conn_read_stream. Note that this function is confusingly + * named and inputs data to the HTTP/3 stack. + */ + if (s->buf_cur == s->buf_total) { + /* Need more data. */ + ec = SSL_read_ex(s->s, s->buf, sizeof(s->buf), &num_bytes); + if (ec <= 0) { + num_bytes = 0; + if (SSL_get_error(s->s, ec) == SSL_ERROR_ZERO_RETURN) { + /* Stream concluded normally. Pass FIN to HTTP/3 stack. */ + ec = nghttp3_conn_read_stream(conn->h3conn, s->id, NULL, 0, + /*fin=*/1); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot pass FIN to nghttp3: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + s->done_recv_fin = 1; + } else if (SSL_get_stream_read_state(s->s) + == SSL_STREAM_STATE_RESET_REMOTE) { + /* Stream was reset by peer. */ + if (!SSL_get_stream_read_error_code(s->s, &aec)) + goto err; + + ec = nghttp3_conn_close_stream(conn->h3conn, s->id, aec); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot mark stream as reset: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + s->done_recv_fin = 1; + } else { + /* Other error. */ + goto err; + } + } + + s->buf_cur = 0; + s->buf_total = num_bytes; + } + + if (s->buf_cur == s->buf_total) + break; + + assert(conn->consumed_app_data == 0); + ec = nghttp3_conn_read_stream(conn->h3conn, s->id, s->buf + s->buf_cur, + s->buf_total - s->buf_cur, /*fin=*/0); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "nghttp3 failed to process incoming data: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + consumed = ec + conn->consumed_app_data; + assert(consumed <= s->buf_total - s->buf_cur); + s->buf_cur += consumed; + conn->consumed_app_data = 0; + } + + return; +err: + conn->pump_res = 0; +} + +int H3_CONN_handle_events(H3_CONN *conn) +{ + int ec, fin; + size_t i, num_vecs, written, total_written, total_len; + int64_t stream_id; + nghttp3_vec vecs[8] = {0}; + H3_STREAM key, *s; + SSL *snew; + + if (conn == NULL) + return 0; + + /* Check for new incoming streams */ + for (;;) { + if ((snew = SSL_accept_stream(conn->qconn, SSL_ACCEPT_STREAM_NO_BLOCK)) == NULL) + break; + + if (h3_conn_accept_stream(conn, snew) == NULL) { + SSL_free(snew); + return 0; + } + } + + /* Pump outgoing data from HTTP/3 engine to QUIC. */ + for (;;) { + /* Get a number of send vectors from the HTTP/3 engine. */ + ec = nghttp3_conn_writev_stream(conn->h3conn, &stream_id, &fin, + vecs, ARRAY_LEN(vecs)); + if (ec < 0) + return 0; + if (ec == 0) + break; + + /* For each of the vectors returned, pass it to OpenSSL QUIC. */ + key.id = stream_id; + if ((s = lh_H3_STREAM_retrieve(conn->streams, &key)) == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "no stream for ID %zd", stream_id); + return 0; + } + + num_vecs = ec; + total_len = nghttp3_vec_len(vecs, num_vecs); + total_written = 0; + for (i = 0; i < num_vecs; ++i) { + if (vecs[i].len == 0) + continue; + + if (s->s == NULL) { + written = vecs[i].len; + } else if (!SSL_write_ex(s->s, vecs[i].base, vecs[i].len, &written)) { + if (SSL_get_error(s->s, 0) == SSL_ERROR_WANT_WRITE) { + written = 0; + nghttp3_conn_block_stream(conn->h3conn, stream_id); + } else { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "writing HTTP/3 data to network failed"); + return 0; + } + } else { + nghttp3_conn_unblock_stream(conn->h3conn, stream_id); + } + + total_written += written; + if (written > 0) { + ec = nghttp3_conn_add_write_offset(conn->h3conn, stream_id, written); + if (ec < 0) + return 0; + + ec = nghttp3_conn_add_ack_offset(conn->h3conn, stream_id, written); + if (ec < 0) + return 0; + } + } + + if (fin && total_written == total_len) { + SSL_stream_conclude(s->s, 0); + if (total_len == 0) { + ec = nghttp3_conn_add_write_offset(conn->h3conn, stream_id, 0); + if (ec < 0) + return 0; + } + } + } + + /* Pump incoming data from QUIC to HTTP/3 engine. */ + conn->pump_res = 1; + lh_H3_STREAM_doall_arg(conn->streams, h3_conn_pump_stream, conn); + if (!conn->pump_res) + return 0; + + return 1; +} + +int H3_CONN_submit_request(H3_CONN *conn, const nghttp3_nv *nva, size_t nvlen, + const nghttp3_data_reader *dr, + void *user_data) +{ + int ec; + H3_STREAM *s_req = NULL; + + if (conn == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER, + "connection must be specified"); + return 0; + } + + if ((s_req = h3_conn_create_stream(conn, H3_STREAM_TYPE_REQ)) == NULL) + goto err; + + s_req->user_data = user_data; + + ec = nghttp3_conn_submit_request(conn->h3conn, s_req->id, nva, nvlen, + dr, s_req); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot submit HTTP/3 request: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + return 1; + +err: + h3_conn_remove_stream(conn, s_req); + return 0; +} diff --git a/demos/http3/ossl-nghttp3.h b/demos/http3/ossl-nghttp3.h new file mode 100644 index 0000000000..5013354947 --- /dev/null +++ b/demos/http3/ossl-nghttp3.h @@ -0,0 +1,96 @@ +#ifndef OSSL_NGHTTP3_H +# define OSSL_NGHTTP3_H + +# include +# include +# include + +/* + * ossl-nghttp3: Demo binding of nghttp3 to OpenSSL QUIC + * ===================================================== + * + * This is a simple library which provides an example binding of the nghttp3 + * HTTP/3 library to OpenSSL's QUIC API. + */ + +/* Represents an HTTP/3 connection to a server. */ +typedef struct h3_conn_st H3_CONN; + +/* Represents an HTTP/3 request, control or QPACK stream. */ +typedef struct h3_stream_st H3_STREAM; + +/* + * Creates a HTTP/3 connection using the given QUIC client connection BIO. The + * BIO must be able to provide an SSL object pointer using BIO_get_ssl. Takes + * ownership of the reference. If the QUIC connection SSL object has not already + * been connected, HTTP/3 ALPN is set automatically. If it has already been + * connected, HTTP/3 ALPN ("h3") must have been configured and no streams must + * have been created yet. + * + * If settings is NULL, use default settings only. Settings unsupported by + * this QUIC binding are ignored. + * + * user_data is an application-provided opaque value which can be retrieved + * using H3_CONN_get_user_data. Note that the user data value passed to the + * callback functions specified in callbacks is a pointer to the H3_CONN, not + * user_data. + * + * Returns NULL on failure. + */ +H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data); + +/* + * Works identically to H3_CONN_new_for_conn except that it manages the creation + * of a QUIC connection SSL object automatically using an address string. addr + * should be a string such as "www.example.com:443". The created underlying QUIC + * connection SSL object is owned by the H3_CONN and can be subsequently + * retrieved using H3_CONN_get0_connection. + * + * Returns NULL on failure. ctx must be a SSL_CTX using a QUIC client + * SSL_METHOD. + */ +H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data); + +/* Equivalent to SSL_connect(H3_CONN_get0_connection(conn)). */ +int H3_CONN_connect(H3_CONN *conn); + +/* + * Free the H3_CONN and any underlying QUIC connection SSL object and associated + * streams. + */ +void H3_CONN_free(H3_CONN *conn); + +/* Returns the user data value which was specified in H3_CONN_new_for_conn. */ +void *H3_CONN_get_user_data(const H3_CONN *conn); + +/* Returns the underlying QUIC connection SSL object. */ +SSL *H3_CONN_get0_connection(const H3_CONN *conn); + +/* + * Handle any pending events on a given HTTP/3 connection. Returns 0 on error. + */ +int H3_CONN_handle_events(H3_CONN *conn); + +/* + * Submits a new HTTP/3 request on the given connection. Returns 0 on error. + * + * This works analogously to nghttp3_conn_submit_request(). The stream user data + * pointer passed to the callbacks is a H3_STREAM object pointer; to retrieve + * the stream user data pointer passed to this function, use + * H3_STREAM_get_user_data. + */ +int H3_CONN_submit_request(H3_CONN *conn, + const nghttp3_nv *hdr, size_t hdrlen, + const nghttp3_data_reader *dr, + void *stream_user_data); + +/* Returns the user data value which was specified in H3_CONN_submit_request. */ +void *H3_STREAM_get_user_data(const H3_STREAM *stream); + +#endif -- Gitee From 3f907f85052bf6189714d9e372fb33814e3d5348 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 13:33:11 +0100 Subject: [PATCH 15/67] QUIC: Add comments to HTTP/3 demo Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/README.md | 33 ++++++++++ demos/http3/ossl-nghttp3.c | 126 +++++++++++++++++++++++++++++++++++-- 2 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 demos/http3/README.md diff --git a/demos/http3/README.md b/demos/http3/README.md new file mode 100644 index 0000000000..35c256d020 --- /dev/null +++ b/demos/http3/README.md @@ -0,0 +1,33 @@ +HTTP/3 Demo using OpenSSL QUIC and nghttp3 +========================================== + +This is a simple demo of how to use HTTP/3 with OpenSSL QUIC using the HTTP/3 +library “nghttp3”. + +The demo is structured into two parts: + +- an adaptation layer which binds nghttp3 to OpenSSL's QUIC implementation + (`ossl-nghttp3.c`); +- a simple application which makes an HTTP/3 request using this adaptation + layer (`ossl-nghttp3-demo.c`). + +The Makefile in this directory can be used to build the demo on \*nix-style +systems. You will need to have the `nghttp3` library available. + +Running the Demo +---------------- + +Depending on your system configuration it may be necessary to set the +`SSL_CERT_FILE` or `SSL_CERT_DIR` environment variables to a location where +trusted root CA certificates can be found. + +After building by running `make`, run `./ossl-nghttp3-demo` with a hostname and +port as the sole argument: + +``` +$ make +$ ./ossl-nghttp3-demo www.google.com:443 +``` + +The demo produces the HTTP response headers in textual form as output followed +by the response body. diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c index 97bf8baec3..927a260ac6 100644 --- a/demos/http3/ossl-nghttp3.c +++ b/demos/http3/ossl-nghttp3.c @@ -245,9 +245,15 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, goto err; } + /* Create the map of stream IDs to H3_STREAM structures. */ if ((conn->streams = lh_H3_STREAM_new(h3_stream_hash, h3_stream_eq)) == NULL) goto err; + /* + * If the application has not started connecting yet, helpfully + * auto-configure ALPN. If the application wants to initiate the connection + * itself, it must take care of this itself. + */ if (SSL_in_before(conn->qconn)) if (SSL_set_alpn_protos(conn->qconn, alpn, sizeof(alpn))) { /* SSL_set_alpn_protos returns 1 on failure */ @@ -256,14 +262,33 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, goto err; } + /* + * We use the QUIC stack in non-blocking mode so that we can react to + * incoming data on different streams, and e.g. incoming streams initiated + * by a server, as and when events occur. + */ BIO_set_nbio(conn->qconn_bio, 1); + /* + * Disable default stream mode and create all streams explicitly. Each QUIC + * stream will be represented by its own QUIC stream SSL object (QSSO). This + * also automatically enables us to accept incoming streams (see + * SSL_set_incoming_stream_policy(3)). + */ if (!SSL_set_default_stream_mode(conn->qconn, SSL_DEFAULT_STREAM_MODE_NONE)) { ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, "failed to configure default stream mode"); goto err; } + /* + * HTTP/3 requires a couple of unidirectional management streams: a control + * stream and some QPACK state management streams for each side of a + * connection. These are the instances on our side (with us sending); the + * server will also create its own equivalent unidirectional streams on its + * side, which we handle subsequently as they come in (see SSL_accept_stream + * in the event handling code below). + */ if ((s_ctl_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_CTRL_SEND)) == NULL) goto err; @@ -281,6 +306,10 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, if (callbacks != NULL) intl_callbacks = *callbacks; + /* + * We need to do some of our own processing when many of these events occur, + * so we note the original callback functions and forward appropriately. + */ conn->recv_data_cb = intl_callbacks.recv_data; conn->stream_close_cb = intl_callbacks.stream_close; conn->stop_sending_cb = intl_callbacks.stop_sending; @@ -293,6 +322,7 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, intl_callbacks.reset_stream = h3_conn_reset_stream; intl_callbacks.deferred_consume = h3_conn_deferred_consume; + /* Create the HTTP/3 client state. */ ec = nghttp3_conn_client_new(&conn->h3conn, &intl_callbacks, settings, NULL, conn); if (ec < 0) { @@ -302,6 +332,14 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, goto err; } + /* + * Tell the HTTP/3 stack which stream IDs are used for our outgoing control + * and QPACK streams. Note that we don't have to tell the HTTP/3 stack what + * IDs are used for incoming streams as this is inferred automatically from + * the stream type byte which starts every incoming unidirectional stream, + * so it will autodetect the correct stream IDs for the incoming control and + * QPACK streams initiated by the server. + */ ec = nghttp3_conn_bind_control_stream(conn->h3conn, s_ctl_send->id); if (ec < 0) { ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, @@ -346,9 +384,14 @@ H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, if ((qconn_bio = BIO_new_ssl_connect(ctx)) == NULL) goto err; + /* Pass the 'hostname:port' string into the ssl_connect BIO. */ if (BIO_set_conn_hostname(qconn_bio, addr) == 0) goto err; + /* + * Get the 'bare' hostname out of the ssl_connect BIO. This is the hostname + * without the port. + */ bare_hostname = BIO_get_conn_hostname(qconn_bio); if (bare_hostname == NULL) goto err; @@ -356,6 +399,7 @@ H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, if (BIO_get_ssl(qconn_bio, &qconn) == 0) goto err; + /* Set the hostname we will validate the X.509 certificate against. */ if (SSL_set1_host(qconn, bare_hostname) <= 0) goto err; @@ -394,11 +438,20 @@ static void h3_conn_pump_stream(H3_STREAM *s, void *conn_) uint64_t aec; if (!conn->pump_res) + /* + * Handling of a previous stream in the iteration over all streams + * failed, so just do nothing. + */ return; for (;;) { - if (s->s == NULL + if (s->s == NULL /* If we already did STOP_SENDING, ignore this stream. */ + /* If this is a write-only stream, there is no read data to check. */ || SSL_get_stream_read_state(s->s) == SSL_STREAM_STATE_WRONG_DIR + /* + * If we already got a FIN for this stream, there is nothing more to + * do for it. + */ || s->done_recv_fin) break; @@ -453,6 +506,11 @@ static void h3_conn_pump_stream(H3_STREAM *s, void *conn_) if (s->buf_cur == s->buf_total) break; + /* + * This function is confusingly named as it is is named from nghttp3's + * 'perspective'; it is used to pass data *into* the HTTP/3 stack which + * has been received from the network. + */ assert(conn->consumed_app_data == 0); ec = nghttp3_conn_read_stream(conn->h3conn, s->id, s->buf + s->buf_cur, s->buf_total - s->buf_cur, /*fin=*/0); @@ -463,6 +521,13 @@ static void h3_conn_pump_stream(H3_STREAM *s, void *conn_) goto err; } + /* + * read_stream reports the data it consumes from us in two different + * ways; the non-application data is returned as a number of bytes 'ec' + * above, but the number of bytes of application data has to be recorded + * by our callback. We sum the two to determine the total number of + * bytes which nghttp3 consumed. + */ consumed = ec + conn->consumed_app_data; assert(consumed <= s->buf_total - s->buf_cur); s->buf_cur += consumed; @@ -486,20 +551,38 @@ int H3_CONN_handle_events(H3_CONN *conn) if (conn == NULL) return 0; - /* Check for new incoming streams */ + /* + * We handle events by doing three things: + * + * 1. Handle new incoming streams + * 2. Pump outgoing data from the HTTP/3 stack to the QUIC engine + * 3. Pump incoming data from the QUIC engine to the HTTP/3 stack + */ + + /* 1. Check for new incoming streams */ for (;;) { if ((snew = SSL_accept_stream(conn->qconn, SSL_ACCEPT_STREAM_NO_BLOCK)) == NULL) break; + /* + * Each new incoming stream gets wrapped into an H3_STREAM object and + * added into our stream ID map. + */ if (h3_conn_accept_stream(conn, snew) == NULL) { SSL_free(snew); return 0; } } - /* Pump outgoing data from HTTP/3 engine to QUIC. */ + /* 2. Pump outgoing data from HTTP/3 engine to QUIC. */ for (;;) { - /* Get a number of send vectors from the HTTP/3 engine. */ + /* + * Get a number of send vectors from the HTTP/3 engine. + * + * Note that this function is confusingly named as it is named from + * nghttp3's 'perspective': this outputs pointers to data which nghttp3 + * wants to *write* to the network. + */ ec = nghttp3_conn_writev_stream(conn->h3conn, &stream_id, &fin, vecs, ARRAY_LEN(vecs)); if (ec < 0) @@ -523,9 +606,14 @@ int H3_CONN_handle_events(H3_CONN *conn) continue; if (s->s == NULL) { + /* Already did STOP_SENDING and threw away stream, ignore */ written = vecs[i].len; } else if (!SSL_write_ex(s->s, vecs[i].base, vecs[i].len, &written)) { if (SSL_get_error(s->s, 0) == SSL_ERROR_WANT_WRITE) { + /* + * We have filled our send buffer so tell nghttp3 to stop + * generating more data; we have to do this explicitly. + */ written = 0; nghttp3_conn_block_stream(conn->h3conn, stream_id); } else { @@ -534,15 +622,30 @@ int H3_CONN_handle_events(H3_CONN *conn) return 0; } } else { + /* + * Tell nghttp3 it can resume generating more data in case we + * previously called block_stream. + */ nghttp3_conn_unblock_stream(conn->h3conn, stream_id); } total_written += written; if (written > 0) { + /* + * Tell nghttp3 we have consumed the data it output when we + * called writev_stream, otherwise subsequent calls to + * writev_stream will output the same data. + */ ec = nghttp3_conn_add_write_offset(conn->h3conn, stream_id, written); if (ec < 0) return 0; + /* + * Tell nghttp3 it can free the buffered data because we will + * not need it again. In our case we can always do this right + * away because we copy the data into our QUIC send buffers + * rather than simply storing a reference to it. + */ ec = nghttp3_conn_add_ack_offset(conn->h3conn, stream_id, written); if (ec < 0) return 0; @@ -550,8 +653,18 @@ int H3_CONN_handle_events(H3_CONN *conn) } if (fin && total_written == total_len) { + /* + * We have written all the data so mark the stream as concluded + * (FIN). + */ SSL_stream_conclude(s->s, 0); + if (total_len == 0) { + /* + * As a special case, if nghttp3 requested to write a + * zero-length stream with a FIN, we have to tell it we did this + * by calling add_write_offset(0). + */ ec = nghttp3_conn_add_write_offset(conn->h3conn, stream_id, 0); if (ec < 0) return 0; @@ -559,8 +672,8 @@ int H3_CONN_handle_events(H3_CONN *conn) } } - /* Pump incoming data from QUIC to HTTP/3 engine. */ - conn->pump_res = 1; + /* 3. Pump incoming data from QUIC to HTTP/3 engine. */ + conn->pump_res = 1; /* cleared in below call if an error occurs */ lh_H3_STREAM_doall_arg(conn->streams, h3_conn_pump_stream, conn); if (!conn->pump_res) return 0; @@ -581,6 +694,7 @@ int H3_CONN_submit_request(H3_CONN *conn, const nghttp3_nv *nva, size_t nvlen, return 0; } + /* Each HTTP/3 request is represented by a stream. */ if ((s_req = h3_conn_create_stream(conn, H3_STREAM_TYPE_REQ)) == NULL) goto err; -- Gitee From 4def44b6cda6d9c3e558d99cff07d75ee882d20e Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 13:33:11 +0100 Subject: [PATCH 16/67] Add copyright headers Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/ossl-nghttp3-demo.c | 8 ++++++++ demos/http3/ossl-nghttp3.c | 8 ++++++++ demos/http3/ossl-nghttp3.h | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/demos/http3/ossl-nghttp3-demo.c b/demos/http3/ossl-nghttp3-demo.c index 53acf31e40..05d5e5b661 100644 --- a/demos/http3/ossl-nghttp3-demo.c +++ b/demos/http3/ossl-nghttp3-demo.c @@ -1,3 +1,11 @@ +/* + * Copyright 2023 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 "ossl-nghttp3.h" #include diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c index 927a260ac6..26ee211f4c 100644 --- a/demos/http3/ossl-nghttp3.c +++ b/demos/http3/ossl-nghttp3.c @@ -1,3 +1,11 @@ +/* + * Copyright 2023 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 "ossl-nghttp3.h" #include #include diff --git a/demos/http3/ossl-nghttp3.h b/demos/http3/ossl-nghttp3.h index 5013354947..78c5ea9866 100644 --- a/demos/http3/ossl-nghttp3.h +++ b/demos/http3/ossl-nghttp3.h @@ -1,3 +1,11 @@ +/* + * Copyright 2023 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_NGHTTP3_H # define OSSL_NGHTTP3_H -- Gitee From da18bf3c3bf41e167ac84992373d724f13046848 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 13:33:11 +0100 Subject: [PATCH 17/67] Add link to nghttp3 Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/demos/http3/README.md b/demos/http3/README.md index 35c256d020..16fe2bad00 100644 --- a/demos/http3/README.md +++ b/demos/http3/README.md @@ -2,7 +2,7 @@ HTTP/3 Demo using OpenSSL QUIC and nghttp3 ========================================== This is a simple demo of how to use HTTP/3 with OpenSSL QUIC using the HTTP/3 -library “nghttp3”. +library “[nghttp3](https://github.com/ngtcp2/nghttp3)”. The demo is structured into two parts: @@ -31,3 +31,8 @@ $ ./ossl-nghttp3-demo www.google.com:443 The demo produces the HTTP response headers in textual form as output followed by the response body. + +See Also +-------- + +- [nghttp3](https://github.com/ngtcp2/nghttp3) -- Gitee From d05b2103e059a5f795d6dcfa91042e4af3c3495e Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 13:33:11 +0100 Subject: [PATCH 18/67] Rename Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/ossl-nghttp3-demo.c | 12 +-- demos/http3/ossl-nghttp3.c | 174 +++++++++++++++++--------------- demos/http3/ossl-nghttp3.h | 73 ++++++++------ 3 files changed, 139 insertions(+), 120 deletions(-) diff --git a/demos/http3/ossl-nghttp3-demo.c b/demos/http3/ossl-nghttp3-demo.c index 05d5e5b661..b1cbd1abf9 100644 --- a/demos/http3/ossl-nghttp3-demo.c +++ b/demos/http3/ossl-nghttp3-demo.c @@ -80,7 +80,7 @@ int main(int argc, char **argv) { int ret = 1; SSL_CTX *ctx = NULL; - H3_CONN *conn = NULL; + OSSL_DEMO_H3_CONN *conn = NULL; nghttp3_nv nva[16]; nghttp3_callbacks callbacks = {0}; size_t num_nv = 0; @@ -110,8 +110,8 @@ int main(int argc, char **argv) callbacks.end_stream = on_end_stream; /* Create connection. */ - if ((conn = H3_CONN_new_for_addr(ctx, addr, &callbacks, - NULL, NULL)) == NULL) { + if ((conn = OSSL_DEMO_H3_CONN_new_for_addr(ctx, addr, &callbacks, + NULL, NULL)) == NULL) { ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, "cannot create HTTP/3 connection"); goto err; @@ -125,7 +125,7 @@ int main(int argc, char **argv) make_nv(&nva[num_nv++], "user-agent", "OpenSSL-Demo/nghttp3"); /* Submit request. */ - if (!H3_CONN_submit_request(conn, nva, num_nv, NULL, NULL)) { + if (!OSSL_DEMO_H3_CONN_submit_request(conn, nva, num_nv, NULL, NULL)) { ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, "cannot submit HTTP/3 request"); goto err; @@ -133,7 +133,7 @@ int main(int argc, char **argv) /* Wait for request to complete. */ while (!done) - if (!H3_CONN_handle_events(conn)) { + if (!OSSL_DEMO_H3_CONN_handle_events(conn)) { ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, "cannot handle events"); goto err; @@ -144,7 +144,7 @@ err: if (ret != 0) ERR_print_errors_fp(stderr); - H3_CONN_free(conn); + OSSL_DEMO_H3_CONN_free(conn); SSL_CTX_free(ctx); return ret; } diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c index 26ee211f4c..20d814c90e 100644 --- a/demos/http3/ossl-nghttp3.c +++ b/demos/http3/ossl-nghttp3.c @@ -13,15 +13,15 @@ #define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0])) enum { - H3_STREAM_TYPE_CTRL_SEND, - H3_STREAM_TYPE_QPACK_ENC_SEND, - H3_STREAM_TYPE_QPACK_DEC_SEND, - H3_STREAM_TYPE_REQ, + OSSL_DEMO_H3_STREAM_TYPE_CTRL_SEND, + OSSL_DEMO_H3_STREAM_TYPE_QPACK_ENC_SEND, + OSSL_DEMO_H3_STREAM_TYPE_QPACK_DEC_SEND, + OSSL_DEMO_H3_STREAM_TYPE_REQ, }; #define BUF_SIZE 4096 -struct h3_stream_st { +struct ossl_demo_h3_stream_st { uint64_t id; /* QUIC stream ID */ SSL *s; /* QUIC stream SSL object */ int done_recv_fin; /* Received FIN */ @@ -31,9 +31,9 @@ struct h3_stream_st { size_t buf_cur, buf_total; }; -DEFINE_LHASH_OF_EX(H3_STREAM); +DEFINE_LHASH_OF_EX(OSSL_DEMO_H3_STREAM); -static void h3_stream_free(H3_STREAM *s) +static void h3_stream_free(OSSL_DEMO_H3_STREAM *s) { if (s == NULL) return; @@ -42,63 +42,68 @@ static void h3_stream_free(H3_STREAM *s) OPENSSL_free(s); } -static unsigned long h3_stream_hash(const H3_STREAM *s) +static unsigned long h3_stream_hash(const OSSL_DEMO_H3_STREAM *s) { return (unsigned long)s->id; } -static int h3_stream_eq(const H3_STREAM *a, const H3_STREAM *b) +static int h3_stream_eq(const OSSL_DEMO_H3_STREAM *a, const OSSL_DEMO_H3_STREAM *b) { if (a->id < b->id) return -1; if (a->id > b->id) return 1; return 0; } -void *H3_STREAM_get_user_data(const H3_STREAM *s) +void *OSSL_DEMO_H3_STREAM_get_user_data(const OSSL_DEMO_H3_STREAM *s) { return s->user_data; } -struct h3_conn_st { - SSL *qconn; /* QUIC connection SSL object */ - BIO *qconn_bio; /* BIO wrapping QCSO */ - nghttp3_conn *h3conn; /* HTTP/3 connection object */ - LHASH_OF(H3_STREAM) *streams; /* map of stream IDs to H3_STREAMs */ - void *user_data; /* opaque user data pointer */ - - int pump_res; - size_t consumed_app_data; +struct ossl_demo_h3_conn_st { + /* QUIC connection SSL object */ + SSL *qconn; + /* BIO wrapping QCSO */ + BIO *qconn_bio; + /* HTTP/3 connection object */ + nghttp3_conn *h3conn; + /* map of stream IDs to OSSL_DEMO_H3_STREAMs */ + LHASH_OF(OSSL_DEMO_H3_STREAM) *streams; + /* opaque user data pointer */ + void *user_data; + + int pump_res; + size_t consumed_app_data; /* Forwarding callbacks */ - nghttp3_recv_data recv_data_cb; - nghttp3_stream_close stream_close_cb; - nghttp3_stop_sending stop_sending_cb; - nghttp3_reset_stream reset_stream_cb; - nghttp3_deferred_consume deferred_consume_cb; + nghttp3_recv_data recv_data_cb; + nghttp3_stream_close stream_close_cb; + nghttp3_stop_sending stop_sending_cb; + nghttp3_reset_stream reset_stream_cb; + nghttp3_deferred_consume deferred_consume_cb; }; -void H3_CONN_free(H3_CONN *conn) +void OSSL_DEMO_H3_CONN_free(OSSL_DEMO_H3_CONN *conn) { if (conn == NULL) return; - lh_H3_STREAM_doall(conn->streams, h3_stream_free); + lh_OSSL_DEMO_H3_STREAM_doall(conn->streams, h3_stream_free); nghttp3_conn_del(conn->h3conn); BIO_free_all(conn->qconn_bio); - lh_H3_STREAM_free(conn->streams); + lh_OSSL_DEMO_H3_STREAM_free(conn->streams); OPENSSL_free(conn); } -static H3_STREAM *h3_conn_create_stream(H3_CONN *conn, int type) +static OSSL_DEMO_H3_STREAM *h3_conn_create_stream(OSSL_DEMO_H3_CONN *conn, int type) { - H3_STREAM *s; + OSSL_DEMO_H3_STREAM *s; uint64_t flags = SSL_STREAM_FLAG_ADVANCE; - if ((s = OPENSSL_zalloc(sizeof(H3_STREAM))) == NULL) + if ((s = OPENSSL_zalloc(sizeof(OSSL_DEMO_H3_STREAM))) == NULL) return NULL; - if (type != H3_STREAM_TYPE_REQ) + if (type != OSSL_DEMO_H3_STREAM_TYPE_REQ) flags |= SSL_STREAM_FLAG_UNI; if ((s->s = SSL_new_stream(conn->qconn, flags)) == NULL) { @@ -108,7 +113,7 @@ static H3_STREAM *h3_conn_create_stream(H3_CONN *conn, int type) } s->id = SSL_get_stream_id(s->s); - lh_H3_STREAM_insert(conn->streams, s); + lh_OSSL_DEMO_H3_STREAM_insert(conn->streams, s); return s; err: @@ -116,25 +121,25 @@ err: return NULL; } -static H3_STREAM *h3_conn_accept_stream(H3_CONN *conn, SSL *qstream) +static OSSL_DEMO_H3_STREAM *h3_conn_accept_stream(OSSL_DEMO_H3_CONN *conn, SSL *qstream) { - H3_STREAM *s; + OSSL_DEMO_H3_STREAM *s; - if ((s = OPENSSL_zalloc(sizeof(H3_STREAM))) == NULL) + if ((s = OPENSSL_zalloc(sizeof(OSSL_DEMO_H3_STREAM))) == NULL) return NULL; s->id = SSL_get_stream_id(qstream); s->s = qstream; - lh_H3_STREAM_insert(conn->streams, s); + lh_OSSL_DEMO_H3_STREAM_insert(conn->streams, s); return s; } -static void h3_conn_remove_stream(H3_CONN *conn, H3_STREAM *s) +static void h3_conn_remove_stream(OSSL_DEMO_H3_CONN *conn, OSSL_DEMO_H3_STREAM *s) { if (s == NULL) return; - lh_H3_STREAM_delete(conn->streams, s); + lh_OSSL_DEMO_H3_STREAM_delete(conn->streams, s); h3_stream_free(s); } @@ -142,7 +147,7 @@ static int h3_conn_recv_data(nghttp3_conn *h3conn, int64_t stream_id, const uint8_t *data, size_t datalen, void *conn_user_data, void *stream_user_data) { - H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_CONN *conn = conn_user_data; conn->consumed_app_data += datalen; if (conn->recv_data_cb == NULL) @@ -157,8 +162,8 @@ static int h3_conn_stream_close(nghttp3_conn *h3conn, int64_t stream_id, void *conn_user_data, void *stream_user_data) { int ret = 0; - H3_CONN *conn = conn_user_data; - H3_STREAM *stream = stream_user_data; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_STREAM *stream = stream_user_data; if (conn->stream_close_cb != NULL) ret = conn->stream_close_cb(h3conn, stream_id, app_error_code, @@ -173,8 +178,8 @@ static int h3_conn_stop_sending(nghttp3_conn *h3conn, int64_t stream_id, void *conn_user_data, void *stream_user_data) { int ret = 0; - H3_CONN *conn = conn_user_data; - H3_STREAM *stream = stream_user_data; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_STREAM *stream = stream_user_data; if (conn->stop_sending_cb != NULL) ret = conn->stop_sending_cb(h3conn, stream_id, app_error_code, @@ -190,8 +195,8 @@ static int h3_conn_reset_stream(nghttp3_conn *h3conn, int64_t stream_id, void *conn_user_data, void *stream_user_data) { int ret = 0; - H3_CONN *conn = conn_user_data; - H3_STREAM *stream = stream_user_data; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_STREAM *stream = stream_user_data; SSL_STREAM_RESET_ARGS args = {0}; if (conn->reset_stream_cb != NULL) @@ -213,7 +218,7 @@ static int h3_conn_deferred_consume(nghttp3_conn *h3conn, int64_t stream_id, void *conn_user_data, void *stream_user_data) { int ret = 0; - H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_CONN *conn = conn_user_data; if (conn->deferred_consume_cb != NULL) ret = conn->deferred_consume_cb(h3conn, stream_id, consumed, @@ -223,14 +228,16 @@ static int h3_conn_deferred_consume(nghttp3_conn *h3conn, int64_t stream_id, return ret; } -H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, - const nghttp3_callbacks *callbacks, - const nghttp3_settings *settings, - void *user_data) +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_conn(BIO *qconn_bio, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data) { int ec; - H3_CONN *conn; - H3_STREAM *s_ctl_send = NULL, *s_qpenc_send = NULL, *s_qpdec_send = NULL; + OSSL_DEMO_H3_CONN *conn; + OSSL_DEMO_H3_STREAM *s_ctl_send = NULL; + OSSL_DEMO_H3_STREAM *s_qpenc_send = NULL; + OSSL_DEMO_H3_STREAM *s_qpdec_send = NULL; nghttp3_settings dsettings = {0}; nghttp3_callbacks intl_callbacks = {0}; static const unsigned char alpn[] = {2, 'h', '3'}; @@ -241,7 +248,7 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, return NULL; } - if ((conn = OPENSSL_zalloc(sizeof(H3_CONN))) == NULL) + if ((conn = OPENSSL_zalloc(sizeof(OSSL_DEMO_H3_CONN))) == NULL) return NULL; conn->qconn_bio = qconn_bio; @@ -253,8 +260,8 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, goto err; } - /* Create the map of stream IDs to H3_STREAM structures. */ - if ((conn->streams = lh_H3_STREAM_new(h3_stream_hash, h3_stream_eq)) == NULL) + /* Create the map of stream IDs to OSSL_DEMO_H3_STREAM structures. */ + if ((conn->streams = lh_OSSL_DEMO_H3_STREAM_new(h3_stream_hash, h3_stream_eq)) == NULL) goto err; /* @@ -297,13 +304,16 @@ H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, * side, which we handle subsequently as they come in (see SSL_accept_stream * in the event handling code below). */ - if ((s_ctl_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_CTRL_SEND)) == NULL) + if ((s_ctl_send + = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_CTRL_SEND)) == NULL) goto err; - if ((s_qpenc_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_QPACK_ENC_SEND)) == NULL) + if ((s_qpenc_send + = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_QPACK_ENC_SEND)) == NULL) goto err; - if ((s_qpdec_send = h3_conn_create_stream(conn, H3_STREAM_TYPE_QPACK_DEC_SEND)) == NULL) + if ((s_qpdec_send + = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_QPACK_DEC_SEND)) == NULL) goto err; if (settings == NULL) { @@ -373,19 +383,19 @@ err: h3_stream_free(s_ctl_send); h3_stream_free(s_qpenc_send); h3_stream_free(s_qpdec_send); - lh_H3_STREAM_free(conn->streams); + lh_OSSL_DEMO_H3_STREAM_free(conn->streams); OPENSSL_free(conn); return NULL; } -H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, - const nghttp3_callbacks *callbacks, - const nghttp3_settings *settings, - void *user_data) +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data) { BIO *qconn_bio = NULL; SSL *qconn = NULL; - H3_CONN *conn = NULL; + OSSL_DEMO_H3_CONN *conn = NULL; const char *bare_hostname; /* QUIC connection setup */ @@ -411,7 +421,8 @@ H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, if (SSL_set1_host(qconn, bare_hostname) <= 0) goto err; - conn = H3_CONN_new_for_conn(qconn_bio, callbacks, settings, user_data); + conn = OSSL_DEMO_H3_CONN_new_for_conn(qconn_bio, callbacks, + settings, user_data); if (conn == NULL) goto err; @@ -422,26 +433,26 @@ err: return NULL; } -int H3_CONN_connect(H3_CONN *conn) +int OSSL_DEMO_H3_CONN_connect(OSSL_DEMO_H3_CONN *conn) { - return SSL_connect(H3_CONN_get0_connection(conn)); + return SSL_connect(OSSL_DEMO_H3_CONN_get0_connection(conn)); } -void *H3_CONN_get_user_data(const H3_CONN *conn) +void *OSSL_DEMO_H3_CONN_get_user_data(const OSSL_DEMO_H3_CONN *conn) { return conn->user_data; } -SSL *H3_CONN_get0_connection(const H3_CONN *conn) +SSL *OSSL_DEMO_H3_CONN_get0_connection(const OSSL_DEMO_H3_CONN *conn) { return conn->qconn; } /* Pumps received data to the HTTP/3 stack for a single stream. */ -static void h3_conn_pump_stream(H3_STREAM *s, void *conn_) +static void h3_conn_pump_stream(OSSL_DEMO_H3_STREAM *s, void *conn_) { int ec; - H3_CONN *conn = conn_; + OSSL_DEMO_H3_CONN *conn = conn_; size_t num_bytes, consumed; uint64_t aec; @@ -547,13 +558,13 @@ err: conn->pump_res = 0; } -int H3_CONN_handle_events(H3_CONN *conn) +int OSSL_DEMO_H3_CONN_handle_events(OSSL_DEMO_H3_CONN *conn) { int ec, fin; size_t i, num_vecs, written, total_written, total_len; int64_t stream_id; nghttp3_vec vecs[8] = {0}; - H3_STREAM key, *s; + OSSL_DEMO_H3_STREAM key, *s; SSL *snew; if (conn == NULL) @@ -573,7 +584,7 @@ int H3_CONN_handle_events(H3_CONN *conn) break; /* - * Each new incoming stream gets wrapped into an H3_STREAM object and + * Each new incoming stream gets wrapped into an OSSL_DEMO_H3_STREAM object and * added into our stream ID map. */ if (h3_conn_accept_stream(conn, snew) == NULL) { @@ -600,7 +611,7 @@ int H3_CONN_handle_events(H3_CONN *conn) /* For each of the vectors returned, pass it to OpenSSL QUIC. */ key.id = stream_id; - if ((s = lh_H3_STREAM_retrieve(conn->streams, &key)) == NULL) { + if ((s = lh_OSSL_DEMO_H3_STREAM_retrieve(conn->streams, &key)) == NULL) { ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, "no stream for ID %zd", stream_id); return 0; @@ -682,19 +693,20 @@ int H3_CONN_handle_events(H3_CONN *conn) /* 3. Pump incoming data from QUIC to HTTP/3 engine. */ conn->pump_res = 1; /* cleared in below call if an error occurs */ - lh_H3_STREAM_doall_arg(conn->streams, h3_conn_pump_stream, conn); + lh_OSSL_DEMO_H3_STREAM_doall_arg(conn->streams, h3_conn_pump_stream, conn); if (!conn->pump_res) return 0; return 1; } -int H3_CONN_submit_request(H3_CONN *conn, const nghttp3_nv *nva, size_t nvlen, - const nghttp3_data_reader *dr, - void *user_data) +int OSSL_DEMO_H3_CONN_submit_request(OSSL_DEMO_H3_CONN *conn, + const nghttp3_nv *nva, size_t nvlen, + const nghttp3_data_reader *dr, + void *user_data) { int ec; - H3_STREAM *s_req = NULL; + OSSL_DEMO_H3_STREAM *s_req = NULL; if (conn == NULL) { ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER, @@ -703,7 +715,7 @@ int H3_CONN_submit_request(H3_CONN *conn, const nghttp3_nv *nva, size_t nvlen, } /* Each HTTP/3 request is represented by a stream. */ - if ((s_req = h3_conn_create_stream(conn, H3_STREAM_TYPE_REQ)) == NULL) + if ((s_req = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_REQ)) == NULL) goto err; s_req->user_data = user_data; diff --git a/demos/http3/ossl-nghttp3.h b/demos/http3/ossl-nghttp3.h index 78c5ea9866..7926d866b1 100644 --- a/demos/http3/ossl-nghttp3.h +++ b/demos/http3/ossl-nghttp3.h @@ -22,10 +22,10 @@ */ /* Represents an HTTP/3 connection to a server. */ -typedef struct h3_conn_st H3_CONN; +typedef struct ossl_demo_h3_conn_st OSSL_DEMO_H3_CONN; /* Represents an HTTP/3 request, control or QPACK stream. */ -typedef struct h3_stream_st H3_STREAM; +typedef struct ossl_demo_h3_stream_st OSSL_DEMO_H3_STREAM; /* * Creates a HTTP/3 connection using the given QUIC client connection BIO. The @@ -39,66 +39,73 @@ typedef struct h3_stream_st H3_STREAM; * this QUIC binding are ignored. * * user_data is an application-provided opaque value which can be retrieved - * using H3_CONN_get_user_data. Note that the user data value passed to the - * callback functions specified in callbacks is a pointer to the H3_CONN, not - * user_data. + * using OSSL_DEMO_H3_CONN_get_user_data. Note that the user data value passed + * to the callback functions specified in callbacks is a pointer to the + * OSSL_DEMO_H3_CONN, not user_data. * * Returns NULL on failure. */ -H3_CONN *H3_CONN_new_for_conn(BIO *qconn_bio, - const nghttp3_callbacks *callbacks, - const nghttp3_settings *settings, - void *user_data); +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_conn(BIO *qconn_bio, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data); /* - * Works identically to H3_CONN_new_for_conn except that it manages the creation - * of a QUIC connection SSL object automatically using an address string. addr - * should be a string such as "www.example.com:443". The created underlying QUIC - * connection SSL object is owned by the H3_CONN and can be subsequently - * retrieved using H3_CONN_get0_connection. + * Works identically to OSSL_DEMO_H3_CONN_new_for_conn except that it manages + * the creation of a QUIC connection SSL object automatically using an address + * string. addr should be a string such as "www.example.com:443". The created + * underlying QUIC connection SSL object is owned by the OSSL_DEMO_H3_CONN and + * can be subsequently retrieved using OSSL_DEMO_H3_CONN_get0_connection. * * Returns NULL on failure. ctx must be a SSL_CTX using a QUIC client * SSL_METHOD. */ -H3_CONN *H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, - const nghttp3_callbacks *callbacks, - const nghttp3_settings *settings, - void *user_data); +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_addr(SSL_CTX *ctx, + const char *addr, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data); -/* Equivalent to SSL_connect(H3_CONN_get0_connection(conn)). */ -int H3_CONN_connect(H3_CONN *conn); +/* Equivalent to SSL_connect(OSSL_DEMO_H3_CONN_get0_connection(conn)). */ +int OSSL_DEMO_H3_CONN_connect(OSSL_DEMO_H3_CONN *conn); /* - * Free the H3_CONN and any underlying QUIC connection SSL object and associated - * streams. + * Free the OSSL_DEMO_H3_CONN and any underlying QUIC connection SSL object and + * associated streams. */ -void H3_CONN_free(H3_CONN *conn); +void OSSL_DEMO_H3_CONN_free(OSSL_DEMO_H3_CONN *conn); -/* Returns the user data value which was specified in H3_CONN_new_for_conn. */ -void *H3_CONN_get_user_data(const H3_CONN *conn); +/* + * Returns the user data value which was specified in + * OSSL_DEMO_H3_CONN_new_for_conn. + */ +void *OSSL_DEMO_H3_CONN_get_user_data(const OSSL_DEMO_H3_CONN *conn); /* Returns the underlying QUIC connection SSL object. */ -SSL *H3_CONN_get0_connection(const H3_CONN *conn); +SSL *OSSL_DEMO_H3_CONN_get0_connection(const OSSL_DEMO_H3_CONN *conn); /* * Handle any pending events on a given HTTP/3 connection. Returns 0 on error. */ -int H3_CONN_handle_events(H3_CONN *conn); +int OSSL_DEMO_H3_CONN_handle_events(OSSL_DEMO_H3_CONN *conn); /* * Submits a new HTTP/3 request on the given connection. Returns 0 on error. * * This works analogously to nghttp3_conn_submit_request(). The stream user data - * pointer passed to the callbacks is a H3_STREAM object pointer; to retrieve - * the stream user data pointer passed to this function, use - * H3_STREAM_get_user_data. + * pointer passed to the callbacks is a OSSL_DEMO_H3_STREAM object pointer; to + * retrieve the stream user data pointer passed to this function, use + * OSSL_DEMO_H3_STREAM_get_user_data. */ -int H3_CONN_submit_request(H3_CONN *conn, +int OSSL_DEMO_H3_CONN_submit_request(OSSL_DEMO_H3_CONN *conn, const nghttp3_nv *hdr, size_t hdrlen, const nghttp3_data_reader *dr, void *stream_user_data); -/* Returns the user data value which was specified in H3_CONN_submit_request. */ -void *H3_STREAM_get_user_data(const H3_STREAM *stream); +/* + * Returns the user data value which was specified in + * OSSL_DEMO_H3_CONN_submit_request. + */ +void *OSSL_DEMO_H3_STREAM_get_user_data(const OSSL_DEMO_H3_STREAM *stream); #endif -- Gitee From 3addbec821611897590d8bc972ab326c0cca0a56 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 14:58:36 +0100 Subject: [PATCH 19/67] Add SNI Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/ossl-nghttp3.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c index 20d814c90e..2b2259f34f 100644 --- a/demos/http3/ossl-nghttp3.c +++ b/demos/http3/ossl-nghttp3.c @@ -421,6 +421,10 @@ OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr if (SSL_set1_host(qconn, bare_hostname) <= 0) goto err; + /* Configure SNI */ + if (!SSL_set_tlsext_host_name(qconn, bare_hostname)) + goto err; + conn = OSSL_DEMO_H3_CONN_new_for_conn(qconn_bio, callbacks, settings, user_data); if (conn == NULL) -- Gitee From a42d0d47be311fe431eb5419d87f2e2ddea02b42 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 15:02:10 +0100 Subject: [PATCH 20/67] Fix markdown Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/22369) Signed-off-by: fly2x --- demos/http3/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/http3/README.md b/demos/http3/README.md index 16fe2bad00..e087aba1e1 100644 --- a/demos/http3/README.md +++ b/demos/http3/README.md @@ -24,7 +24,7 @@ trusted root CA certificates can be found. After building by running `make`, run `./ossl-nghttp3-demo` with a hostname and port as the sole argument: -``` +```shell $ make $ ./ossl-nghttp3-demo www.google.com:443 ``` -- Gitee From af14ab2166932788447f3cdf1089c0d7e633c293 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 9 Oct 2023 11:36:50 +0200 Subject: [PATCH 21/67] apps: Print out a proper message when a store cannot be opened Fixes #22306 Reviewed-by: David von Oheimb Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/22318) Signed-off-by: fly2x --- apps/lib/apps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 6b2a4b86ce..945ac1e716 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -1003,10 +1003,16 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, ctx = OSSL_STORE_open_ex(uri, libctx, propq, get_ui_method(), &uidata, params, NULL, NULL); } - if (ctx == NULL) + if (ctx == NULL) { + if (!quiet) + BIO_printf(bio_err, "Could not open file or uri for loading"); goto end; - if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) + } + if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) { + if (!quiet) + BIO_printf(bio_err, "Internal error trying to load"); goto end; + } failed = NULL; while ((ppkey != NULL || ppubkey != NULL || pparams != NULL -- Gitee From e5236fc66da7a9ac7968edc7f19386412e8878c3 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 9 Oct 2023 11:39:12 +0200 Subject: [PATCH 22/67] apps.c: Remove a redundant error print-out Reviewed-by: David von Oheimb Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/22318) Signed-off-by: fly2x --- apps/lib/apps.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 945ac1e716..47d994b9c2 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -1106,8 +1106,6 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, failed = FAIL_NAME; if (failed != NULL && !quiet) BIO_printf(bio_err, "Could not find"); - } else if (!quiet) { - BIO_printf(bio_err, "Could not read"); } if (failed != NULL && !quiet) { unsigned long err = ERR_peek_last_error(); -- Gitee From 675c2b47f149908fdc8c0f054eaac221ef90585e Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 19 Oct 2023 09:18:37 +0200 Subject: [PATCH 23/67] Do not include crypto/asn1.h from internal/cryptlib.h This is unnecessary and conceptualy wrong as headers from internal should not include headers from crypto Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22432) Signed-off-by: fly2x --- crypto/asn1/asn1_gen.c | 3 ++- crypto/x509/v3_addr.c | 3 ++- include/internal/cryptlib.h | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/asn1/asn1_gen.c b/crypto/asn1/asn1_gen.c index 2b27624d8a..6f73449cf4 100644 --- a/crypto/asn1/asn1_gen.c +++ b/crypto/asn1/asn1_gen.c @@ -7,9 +7,10 @@ * https://www.openssl.org/source/license.html */ -#include "internal/cryptlib.h" #include #include +#include "internal/cryptlib.h" +#include "crypto/asn1.h" #define ASN1_GEN_FLAG 0x10000 #define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1) diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c index f4c8de2d16..b990d54048 100644 --- a/crypto/x509/v3_addr.c +++ b/crypto/x509/v3_addr.c @@ -16,12 +16,13 @@ #include #include -#include "internal/cryptlib.h" #include #include #include #include #include +#include "internal/cryptlib.h" +#include "crypto/asn1.h" #include "crypto/x509.h" #include "ext_dat.h" #include "x509_local.h" diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 843a720b8f..64851fd8ed 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -19,7 +19,6 @@ # endif # include "internal/common.h" -# include "crypto/asn1.h" # include # include -- Gitee From 5aec048ee620cb2573de2d985091f899aa0a96be Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 19 Oct 2023 09:23:43 +0200 Subject: [PATCH 24/67] cms_enc.c: Include crypto/asn1.h for struct asn1_object_st Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22432) Signed-off-by: fly2x --- crypto/cms/cms_enc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c index 3f1328c041..ea8f07e1af 100644 --- a/crypto/cms/cms_enc.c +++ b/crypto/cms/cms_enc.c @@ -15,6 +15,7 @@ #include #include #include "crypto/evp.h" +#include "crypto/asn1.h" #include "cms_local.h" /* CMS EncryptedData Utilities */ -- Gitee From 480cc9fc3f94585c3ad7612e2591a5262cecaa23 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 17 Oct 2023 16:26:13 +0100 Subject: [PATCH 25/67] Ignore retry packets that arrive too late RFC 9000 s 17.2.5.2 says > After the client has received and processed an Initial or Retry packet > from the server, it MUST discard any subsequent Retry packets that it > receives. We were checking for multiple Retry packets, but not if we had already processed an Initial packet. Fixes the assertion failure noted in https://github.com/openssl/openssl/pull/22368#issuecomment-1765618884 Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22411) Signed-off-by: fly2x --- ssl/quic/quic_channel.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 3da0caa4ea..a6ed14664e 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2220,6 +2220,14 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch) */ return; + /* + * RFC 9000 s 17.2.5.2: After the client has received and processed an + * Initial or Retry packet from the server, it MUST discard any + * subsequent Retry packets that it receives. + */ + if (ch->have_received_enc_pkt) + return; + if (ch->qrx_pkt->hdr->len <= QUIC_RETRY_INTEGRITY_TAG_LEN) /* Packets with zero-length Retry Tokens are invalid. */ return; -- Gitee From e90ea494052fc1e3442fb8bcd90c933a93e72a62 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 17 Oct 2023 14:55:48 +0100 Subject: [PATCH 26/67] Ignore ping deadline when calculating tick deadline if we can't send If the CC TX allowance is zero then we cannot send a PING frame at the moment, so do not take into account the ping deadline when calculating the tick deadline in that case. This avoids the hang found by the fuzzer mentioned in https://github.com/openssl/openssl/pull/22368#issuecomment-1765131727 Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22410) Signed-off-by: fly2x --- ssl/quic/quic_channel.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index a6ed14664e..0462fd2411 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2598,6 +2598,13 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) ossl_quic_enc_level_to_pn_space(i))); } } + + /* + * When do we need to send an ACK-eliciting packet to reset the idle + * deadline timer for the peer? + */ + if (!ossl_time_is_infinite(ch->ping_deadline)) + deadline = ossl_time_min(deadline, ch->ping_deadline); } /* Apply TXP wakeup deadline. */ @@ -2612,14 +2619,6 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) deadline = ossl_time_min(deadline, ch->idle_deadline); - /* - * When do we need to send an ACK-eliciting packet to reset the idle - * deadline timer for the peer? - */ - if (!ossl_time_is_infinite(ch->ping_deadline)) - deadline = ossl_time_min(deadline, - ch->ping_deadline); - /* When does the RXKU process complete? */ if (ch->rxku_in_progress) deadline = ossl_time_min(deadline, ch->rxku_update_end_deadline); -- Gitee From 873c16f336c3dfa0d6ef11cb1ae3ebfea3830959 Mon Sep 17 00:00:00 2001 From: "Matthias St. Pierre" Date: Mon, 16 Oct 2023 23:48:03 +0200 Subject: [PATCH 27/67] rand: add callbacks to cleanup the user entropy resp. nonce The `get_user_{entropy,nonce}` callbacks were add recently to the dispatch table in commit 4cde7585ce8e. Instead of adding corresponding `cleanup_user_{entropy,nonce}` callbacks, the `cleanup_{entropy,nonce}` callbacks were reused. This can cause a problem in the case where the seed source is replaced by a provider: the buffer gets allocated by the provider but cleared by the core. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22423) Signed-off-by: fly2x --- crypto/provider_core.c | 26 +++++++++++++++++---- crypto/rand/prov_seed.c | 12 ++++++++++ doc/internal/man3/ossl_rand_get_entropy.pod | 23 +++++++++++++----- doc/man7/provider-base.pod | 26 +++++++++++++++------ include/crypto/rand.h | 4 ++++ include/openssl/core_dispatch.h | 6 +++++ providers/common/provider_seeding.c | 24 +++++++++++++++---- 7 files changed, 100 insertions(+), 21 deletions(-) diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 266934937c..838bcd161c 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -1930,12 +1930,14 @@ OSSL_FUNC_BIO_free_fn ossl_core_bio_free; OSSL_FUNC_BIO_vprintf_fn ossl_core_bio_vprintf; OSSL_FUNC_BIO_vsnprintf_fn BIO_vsnprintf; static OSSL_FUNC_self_test_cb_fn core_self_test_get_callback; -static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy; static OSSL_FUNC_get_entropy_fn rand_get_entropy; +static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy; static OSSL_FUNC_cleanup_entropy_fn rand_cleanup_entropy; -static OSSL_FUNC_get_user_nonce_fn rand_get_user_nonce; +static OSSL_FUNC_cleanup_user_entropy_fn rand_cleanup_user_entropy; static OSSL_FUNC_get_nonce_fn rand_get_nonce; +static OSSL_FUNC_get_user_nonce_fn rand_get_user_nonce; static OSSL_FUNC_cleanup_nonce_fn rand_cleanup_nonce; +static OSSL_FUNC_cleanup_user_nonce_fn rand_cleanup_user_nonce; #endif OSSL_FUNC_CRYPTO_malloc_fn CRYPTO_malloc; OSSL_FUNC_CRYPTO_zalloc_fn CRYPTO_zalloc; @@ -2119,6 +2121,13 @@ static void rand_cleanup_entropy(const OSSL_CORE_HANDLE *handle, buf, len); } +static void rand_cleanup_user_entropy(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len) +{ + ossl_rand_cleanup_user_entropy((OSSL_LIB_CTX *)core_get_libctx(handle), + buf, len); +} + static size_t rand_get_nonce(const OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, @@ -2144,6 +2153,13 @@ static void rand_cleanup_nonce(const OSSL_CORE_HANDLE *handle, buf, len); } +static void rand_cleanup_user_nonce(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len) +{ + ossl_rand_cleanup_user_nonce((OSSL_LIB_CTX *)core_get_libctx(handle), + buf, len); +} + static const char *core_provider_get0_name(const OSSL_CORE_HANDLE *prov) { return OSSL_PROVIDER_get0_name((const OSSL_PROVIDER *)prov); @@ -2238,11 +2254,13 @@ static const OSSL_DISPATCH core_dispatch_[] = { { OSSL_FUNC_BIO_VSNPRINTF, (void (*)(void))BIO_vsnprintf }, { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))core_self_test_get_callback }, { OSSL_FUNC_GET_ENTROPY, (void (*)(void))rand_get_entropy }, + { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy }, { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))rand_cleanup_entropy }, + { OSSL_FUNC_CLEANUP_USER_ENTROPY, (void (*)(void))rand_cleanup_user_entropy }, { OSSL_FUNC_GET_NONCE, (void (*)(void))rand_get_nonce }, - { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))rand_cleanup_nonce }, - { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy }, { OSSL_FUNC_GET_USER_NONCE, (void (*)(void))rand_get_user_nonce }, + { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))rand_cleanup_nonce }, + { OSSL_FUNC_CLEANUP_USER_NONCE, (void (*)(void))rand_cleanup_user_nonce }, #endif { OSSL_FUNC_CRYPTO_MALLOC, (void (*)(void))CRYPTO_malloc }, { OSSL_FUNC_CRYPTO_ZALLOC, (void (*)(void))CRYPTO_zalloc }, diff --git a/crypto/rand/prov_seed.c b/crypto/rand/prov_seed.c index af35e02475..a8128119b5 100644 --- a/crypto/rand/prov_seed.c +++ b/crypto/rand/prov_seed.c @@ -77,6 +77,12 @@ void ossl_rand_cleanup_entropy(ossl_unused OSSL_LIB_CTX *ctx, OPENSSL_secure_clear_free(buf, len); } +void ossl_rand_cleanup_user_entropy(OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len) +{ + OPENSSL_secure_clear_free(buf, len); +} + size_t ossl_rand_get_nonce(ossl_unused OSSL_LIB_CTX *ctx, unsigned char **pout, size_t min_len, ossl_unused size_t max_len, @@ -130,3 +136,9 @@ void ossl_rand_cleanup_nonce(ossl_unused OSSL_LIB_CTX *ctx, { OPENSSL_clear_free(buf, len); } + +void ossl_rand_cleanup_user_nonce(ossl_unused OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len) +{ + OPENSSL_clear_free(buf, len); +} diff --git a/doc/internal/man3/ossl_rand_get_entropy.pod b/doc/internal/man3/ossl_rand_get_entropy.pod index 5c7a076336..be39369f2b 100644 --- a/doc/internal/man3/ossl_rand_get_entropy.pod +++ b/doc/internal/man3/ossl_rand_get_entropy.pod @@ -2,8 +2,10 @@ =head1 NAME -ossl_rand_get_entropy, ossl_rand_get_user_entropy, ossl_rand_cleanup_entropy, -ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce +ossl_rand_get_entropy, ossl_rand_get_user_entropy, +ossl_rand_cleanup_entropy, ossl_rand_cleanup_user_entropy, +ossl_rand_get_nonce, ossl_rand_get_user_nonce, +ossl_rand_cleanup_nonce, ossl_rand_cleanup_user_nonce - get seed material from the operating system =head1 SYNOPSIS @@ -18,6 +20,8 @@ ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce size_t min_len, size_t max_len); void ossl_rand_cleanup_entropy(OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void ossl_rand_cleanup_user_entropy(OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); size_t ossl_rand_get_nonce(OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, size_t salt_len); @@ -26,6 +30,8 @@ ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce const void *salt, size_t salt_len); void ossl_rand_cleanup_nonce(OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void ossl_rand_cleanup_user_nonce(OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); =head1 DESCRIPTION @@ -41,8 +47,12 @@ DRBG seed source. By default this is the operating system but it can be changed by calling L. ossl_rand_cleanup_entropy() cleanses and frees any storage allocated by -ossl_rand_get_entropy() or ossl_rand_get_user_entropy(). The entropy -buffer is pointed to by I and is of length I bytes. +ossl_rand_get_entropy(). The entropy buffer is pointed to by I +and is of length I bytes. + +ossl_rand_cleanup_user_entropy() cleanses and frees any storage allocated by +ossl_rand_get_user_entropy(). The entropy buffer is pointed to by I +and is of length I bytes. ossl_rand_get_nonce() retrieves a nonce using the passed I parameter of length I and operating system specific information. @@ -76,8 +86,9 @@ of bytes in I<*pout> or 0 on error. =head1 HISTORY -The functions ossl_rand_get_user_entropy() and ossl_rand_get_user_nonce() -were added in OpenSSL 3.0.12, 3.1.4 and 3.2.0. +The functions ossl_rand_get_user_entropy(), ossl_rand_get_user_nonce(), +ossl_rand_cleanup_user_entropy(), and ossl_rand_cleanup_user_nonce() +were added in OpenSSL 3.1.4 and 3.2.0. The remaining functions described here were all added in OpenSSL 3.0. diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod index eb9e8d3575..5dcbbed221 100644 --- a/doc/man7/provider-base.pod +++ b/doc/man7/provider-base.pod @@ -81,6 +81,8 @@ provider-base size_t min_len, size_t max_len); void cleanup_entropy(const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void cleanup_user_entropy(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); size_t get_nonce(const OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, size_t salt_len); @@ -89,6 +91,8 @@ provider-base const void *salt, size_t salt_len); void cleanup_nonce(const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void cleanup_user_nonce(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); /* Functions for querying the providers in the application library context */ int provider_register_child_cb(const OSSL_CORE_HANDLE *handle, @@ -179,9 +183,11 @@ provider): ossl_rand_get_entropy OSSL_FUNC_GET_ENTROPY ossl_rand_get_user_entropy OSSL_FUNC_GET_USER_ENTROPY ossl_rand_cleanup_entropy OSSL_FUNC_CLEANUP_ENTROPY + ossl_rand_cleanup_user_entropy OSSL_FUNC_CLEANUP_USER_ENTROPY ossl_rand_get_nonce OSSL_FUNC_GET_NONCE ossl_rand_get_user_nonce OSSL_FUNC_GET_USER_NONCE ossl_rand_cleanup_nonce OSSL_FUNC_CLEANUP_NONCE + ossl_rand_cleanup_user_nonce OSSL_FUNC_CLEANUP_USER_NONCE provider_register_child_cb OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB provider_deregister_child_cb OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB provider_name OSSL_FUNC_PROVIDER_NAME @@ -315,9 +321,12 @@ attempt to gather seed material via the seed source specified by a call to L or via L. cleanup_entropy() is used to clean up and free the buffer returned by -get_entropy() or get_user_entropy(). The entropy pointer returned by -get_entropy() or get_user_entropy() is passed in B and its length -in B. +get_entropy(). The entropy pointer returned by get_entropy() +is passed in B and its length in B. + +cleanup_user_entropy() is used to clean up and free the buffer returned by +get_user_entropy(). The entropy pointer returned by get_user_entropy() +is passed in B and its length in B. get_nonce() retrieves a nonce using the passed I parameter of length I and operating system specific information. @@ -331,10 +340,13 @@ get_user_nonce() is the same as get_nonce() except that it will attempt to gather seed material via the seed source specified by a call to L or via L. -cleanup_nonce() is used to clean up and free the buffer returned -by get_nonce() or get_user_nonce(). The nonce pointer returned by -get_nonce() or get_user_nonce() is passed in B and its length -in B. +cleanup_nonce() is used to clean up and free the buffer returned by +get_nonce(). The nonce pointer returned by get_nonce() +is passed in B and its length in B. + +cleanup_user_nonce() is used to clean up and free the buffer returned by +get_user_nonce(). The nonce pointer returned by get_user_nonce() +is passed in B and its length in B. provider_register_child_cb() registers callbacks for being informed about the loading and unloading of providers in the application's library context. diff --git a/include/crypto/rand.h b/include/crypto/rand.h index 5841cccaa6..215b3b7af3 100644 --- a/include/crypto/rand.h +++ b/include/crypto/rand.h @@ -116,6 +116,8 @@ size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx, size_t min_len, size_t max_len); void ossl_rand_cleanup_entropy(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t len); +void ossl_rand_cleanup_user_entropy(OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len); size_t ossl_rand_get_nonce(OSSL_LIB_CTX *ctx, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, size_t salt_len); @@ -124,6 +126,8 @@ size_t ossl_rand_get_user_nonce(OSSL_LIB_CTX *ctx, unsigned char **pout, const void *salt, size_t salt_len); void ossl_rand_cleanup_nonce(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t len); +void ossl_rand_cleanup_user_nonce(OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len); /* * Get seeding material from the operating system sources. diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h index 6c952f18aa..9b03f20c3b 100644 --- a/include/openssl/core_dispatch.h +++ b/include/openssl/core_dispatch.h @@ -177,6 +177,8 @@ OSSL_CORE_MAKE_FUNC(int, BIO_ctrl, (OSSL_CORE_BIO *bio, int cmd, long num, void *ptr)) /* New seeding functions prototypes with the 101-104 series */ +#define OSSL_FUNC_CLEANUP_USER_ENTROPY 96 +#define OSSL_FUNC_CLEANUP_USER_NONCE 97 #define OSSL_FUNC_GET_USER_ENTROPY 98 #define OSSL_FUNC_GET_USER_NONCE 99 @@ -197,6 +199,8 @@ OSSL_CORE_MAKE_FUNC(size_t, get_user_entropy, (const OSSL_CORE_HANDLE *handle, size_t min_len, size_t max_len)) OSSL_CORE_MAKE_FUNC(void, cleanup_entropy, (const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len)) +OSSL_CORE_MAKE_FUNC(void, cleanup_user_entropy, (const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len)) OSSL_CORE_MAKE_FUNC(size_t, get_nonce, (const OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, @@ -207,6 +211,8 @@ OSSL_CORE_MAKE_FUNC(size_t, get_user_nonce, (const OSSL_CORE_HANDLE *handle, size_t salt_len)) OSSL_CORE_MAKE_FUNC(void, cleanup_nonce, (const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len)) +OSSL_CORE_MAKE_FUNC(void, cleanup_user_nonce, (const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len)) /* Functions to access the core's providers */ #define OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB 105 diff --git a/providers/common/provider_seeding.c b/providers/common/provider_seeding.c index c7b2ea6da6..544344f30a 100644 --- a/providers/common/provider_seeding.c +++ b/providers/common/provider_seeding.c @@ -14,9 +14,11 @@ static OSSL_FUNC_get_entropy_fn *c_get_entropy = NULL; static OSSL_FUNC_get_user_entropy_fn *c_get_user_entropy = NULL; static OSSL_FUNC_cleanup_entropy_fn *c_cleanup_entropy = NULL; +static OSSL_FUNC_cleanup_user_entropy_fn *c_cleanup_user_entropy = NULL; static OSSL_FUNC_get_nonce_fn *c_get_nonce = NULL; static OSSL_FUNC_get_user_nonce_fn *c_get_user_nonce = NULL; static OSSL_FUNC_cleanup_nonce_fn *c_cleanup_nonce = NULL; +static OSSL_FUNC_cleanup_user_nonce_fn *c_cleanup_user_nonce = NULL; #ifdef FIPS_MODULE /* @@ -56,6 +58,9 @@ int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns) case OSSL_FUNC_CLEANUP_ENTROPY: set_func(c_cleanup_entropy, OSSL_FUNC_cleanup_entropy(fns)); break; + case OSSL_FUNC_CLEANUP_USER_ENTROPY: + set_func(c_cleanup_user_entropy, OSSL_FUNC_cleanup_user_entropy(fns)); + break; case OSSL_FUNC_GET_NONCE: set_func(c_get_nonce, OSSL_FUNC_get_nonce(fns)); break; @@ -65,6 +70,9 @@ int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns) case OSSL_FUNC_CLEANUP_NONCE: set_func(c_cleanup_nonce, OSSL_FUNC_cleanup_nonce(fns)); break; + case OSSL_FUNC_CLEANUP_USER_NONCE: + set_func(c_cleanup_user_nonce, OSSL_FUNC_cleanup_user_nonce(fns)); + break; } #undef set_func } @@ -86,8 +94,12 @@ size_t ossl_prov_get_entropy(PROV_CTX *prov_ctx, unsigned char **pout, void ossl_prov_cleanup_entropy(PROV_CTX *prov_ctx, unsigned char *buf, size_t len) { - if (c_cleanup_entropy != NULL) - c_cleanup_entropy(CORE_HANDLE(prov_ctx), buf, len); + const OSSL_CORE_HANDLE *handle = CORE_HANDLE(prov_ctx); + + if (c_cleanup_user_entropy != NULL) + c_cleanup_user_entropy(handle, buf, len); + else if (c_cleanup_entropy != NULL) + c_cleanup_entropy(handle, buf, len); } size_t ossl_prov_get_nonce(PROV_CTX *prov_ctx, unsigned char **pout, @@ -105,6 +117,10 @@ size_t ossl_prov_get_nonce(PROV_CTX *prov_ctx, unsigned char **pout, void ossl_prov_cleanup_nonce(PROV_CTX *prov_ctx, unsigned char *buf, size_t len) { - if (c_cleanup_nonce != NULL) - c_cleanup_nonce(CORE_HANDLE(prov_ctx), buf, len); + const OSSL_CORE_HANDLE *handle = CORE_HANDLE(prov_ctx); + + if (c_cleanup_user_nonce != NULL) + c_cleanup_user_nonce(handle, buf, len); + else if (c_cleanup_nonce != NULL) + c_cleanup_nonce(handle, buf, len); } -- Gitee From 42ffa7b8aa05eb81a20fc79d7319f09ab340ab68 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 17 Oct 2023 08:58:22 +0200 Subject: [PATCH 28/67] Postpone two TODO(QUIC) items appropriately The one in ch_rx_handle_packet() is a tuning thing -> QUIC FUTURE The one in ossl_quic_tserver_shutdown() is a server thing -> QUIC SERVER Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22408) Signed-off-by: fly2x --- ssl/quic/quic_channel.c | 2 +- ssl/quic/quic_tserver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 0462fd2411..3b9993b96a 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2302,7 +2302,7 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch) * non-zero Token Length field MUST either discard the packet or * generate a connection error of type PROTOCOL_VIOLATION. * - * TODO(QUIC): consider the implications of RFC 9000 s. 10.2.3 + * TODO(QUIC FUTURE): consider the implications of RFC 9000 s. 10.2.3 * Immediate Close during the Handshake: * However, at the cost of reducing feedback about * errors for legitimate peers, some forms of denial of diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index 3630577e70..3fc51b4a77 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -508,7 +508,7 @@ int ossl_quic_tserver_shutdown(QUIC_TSERVER *srv, uint64_t app_error_code) { ossl_quic_channel_local_close(srv->ch, app_error_code, NULL); - /* TODO(QUIC): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */ + /* TODO(QUIC SERVER): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */ if (ossl_quic_channel_is_terminated(srv->ch)) return 1; -- Gitee From 36708e0faa30446f61c6ef0e0670fb02376b09d5 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 17 Oct 2023 10:00:58 +0200 Subject: [PATCH 29/67] QUIC: Add handling of SSL_get_shutdown() Return SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN with semantics similar to TLS connections. Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22408) Signed-off-by: fly2x --- doc/man3/SSL_CTX_set_quiet_shutdown.pod | 5 +-- doc/man3/SSL_set_shutdown.pod | 12 +++++-- include/internal/quic_channel.h | 1 + include/internal/quic_ssl.h | 1 + ssl/quic/quic_channel.c | 2 +- ssl/quic/quic_impl.c | 21 +++++++++++ ssl/ssl_lib.c | 13 ++++--- test/quicapitest.c | 47 +++++++++++++++++++++++++ 8 files changed, 93 insertions(+), 9 deletions(-) diff --git a/doc/man3/SSL_CTX_set_quiet_shutdown.pod b/doc/man3/SSL_CTX_set_quiet_shutdown.pod index b7c2a32069..4894e2f5d2 100644 --- a/doc/man3/SSL_CTX_set_quiet_shutdown.pod +++ b/doc/man3/SSL_CTX_set_quiet_shutdown.pod @@ -2,7 +2,8 @@ =head1 NAME -SSL_CTX_set_quiet_shutdown, SSL_CTX_get_quiet_shutdown, SSL_set_quiet_shutdown, SSL_get_quiet_shutdown - manipulate shutdown behaviour +SSL_CTX_set_quiet_shutdown, SSL_CTX_get_quiet_shutdown, SSL_set_quiet_shutdown, +SSL_get_quiet_shutdown - manipulate shutdown behaviour =head1 SYNOPSIS @@ -54,7 +55,7 @@ The default is normal shutdown behaviour as described by the TLS standard. SSL_CTX_set_quiet_shutdown() and SSL_set_quiet_shutdown() do not return diagnostic information. -SSL_CTX_get_quiet_shutdown() and SSL_get_quiet_shutdown return the current +SSL_CTX_get_quiet_shutdown() and SSL_get_quiet_shutdown() return the current setting. =head1 SEE ALSO diff --git a/doc/man3/SSL_set_shutdown.pod b/doc/man3/SSL_set_shutdown.pod index c3b613a247..9a7eb463a8 100644 --- a/doc/man3/SSL_set_shutdown.pod +++ b/doc/man3/SSL_set_shutdown.pod @@ -57,13 +57,21 @@ If a close_notify was received, SSL_RECEIVED_SHUTDOWN will be set, for setting SSL_SENT_SHUTDOWN the application must however still call L or SSL_set_shutdown() itself. -These functions are not supported for QUIC SSL objects. +SSL_set_shutdown() is not supported for QUIC SSL objects. =head1 RETURN VALUES SSL_set_shutdown() does not return diagnostic information. -SSL_get_shutdown() returns the current setting. +SSL_get_shutdown() returns the current shutdown state as set or based +on the actual connection state. + +SSL_get_shutdown() returns 0 if called on a QUIC stream SSL object. If it +is called on a QUIC connection SSL object, it returns a value with +SSL_SENT_SHUTDOWN set if CONNECTION_CLOSE has been sent to the peer and +it returns a value with SSL_RECEIVED_SHUTDOWN set if CONNECTION_CLOSE +has been received from the peer or the QUIC connection is fully terminated +for other reasons. =head1 SEE ALSO diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index 0841001c23..f46db0637e 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -320,6 +320,7 @@ QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch, int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch); const QUIC_TERMINATE_CAUSE * ossl_quic_channel_get_terminate_cause(const QUIC_CHANNEL *ch); +int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch); diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index 66cea1bfe1..52d4527c81 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -125,6 +125,7 @@ void ossl_quic_conn_force_assist_thread_wake(SSL *s); QUIC_CHANNEL *ossl_quic_conn_get_channel(SSL *s); int ossl_quic_has_pending(const SSL *s); +int ossl_quic_get_shutdown(const SSL *s); # endif diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 3b9993b96a..8e75eda539 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -635,7 +635,7 @@ int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch) return ch != NULL && ch->state == QUIC_CHANNEL_STATE_ACTIVE; } -static int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch) +int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch) { return ch->state == QUIC_CHANNEL_STATE_TERMINATING_CLOSING; } diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 29a283dca0..bdf5d5fea8 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -3571,6 +3571,27 @@ const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u) return NULL; } +/* + * SSL_get_shutdown() + * ------------------ + */ +int ossl_quic_get_shutdown(const SSL *s) +{ + QCTX ctx; + int shut = 0; + + if (!expect_quic_conn_only(s, &ctx)) + return 0; + + if (ossl_quic_channel_is_term_any(ctx.qc->ch)) { + shut |= SSL_SENT_SHUTDOWN; + if (!ossl_quic_channel_is_closing(ctx.qc->ch)) + shut |= SSL_RECEIVED_SHUTDOWN; + } + + return shut; +} + /* * Internal Testing APIs * ===================== diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f15fe126a2..bd9160b756 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5142,7 +5142,7 @@ void SSL_set_quiet_shutdown(SSL *s, int mode) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s); - /* TODO(QUIC): Currently not supported for QUIC. */ + /* Not supported with QUIC */ if (sc == NULL) return; @@ -5153,7 +5153,7 @@ int SSL_get_quiet_shutdown(const SSL *s) { const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s); - /* TODO(QUIC): Currently not supported for QUIC. */ + /* Not supported with QUIC */ if (sc == NULL) return 0; @@ -5164,7 +5164,7 @@ void SSL_set_shutdown(SSL *s, int mode) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s); - /* TODO(QUIC): Do we want this for QUIC? */ + /* Not supported with QUIC */ if (sc == NULL) return; @@ -5175,7 +5175,12 @@ int SSL_get_shutdown(const SSL *s) { const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s); - /* TODO(QUIC): Do we want this for QUIC? */ +#ifndef OPENSSL_NO_QUIC + /* QUIC: Just indicate whether the connection was shutdown cleanly. */ + if (IS_QUIC(s)) + return ossl_quic_get_shutdown(s); +#endif + if (sc == NULL) return 0; diff --git a/test/quicapitest.c b/test/quicapitest.c index 81c8c215bd..37d7803005 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -1335,6 +1335,52 @@ static int test_alpn(int idx) return testresult; } +/* + * Test SSL_get_shutdown() behavior. + */ +static int test_get_shutdown(void) +{ + SSL_CTX *cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method()); + SSL *clientquic = NULL; + QUIC_TSERVER *qtserv = NULL; + int testresult = 0; + + if (!TEST_ptr(cctx) + || !TEST_true(qtest_create_quic_objects(libctx, cctx, NULL, cert, + privkey, + QTEST_FLAG_FAKE_TIME, + &qtserv, &clientquic, + NULL, NULL)) + || !TEST_true(qtest_create_quic_connection(qtserv, clientquic))) + goto err; + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), 0)) + goto err; + + if (!TEST_int_eq(SSL_shutdown(clientquic), 0)) + goto err; + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), SSL_SENT_SHUTDOWN)) + goto err; + + do { + ossl_quic_tserver_tick(qtserv); + qtest_add_time(100); + } while (SSL_shutdown(clientquic) == 0); + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), + SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) + goto err; + + testresult = 1; + err: + ossl_quic_tserver_free(qtserv); + SSL_free(clientquic); + SSL_CTX_free(cctx); + + return testresult; +} + #define MAX_LOOPS 2000 /* @@ -1586,6 +1632,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_client_auth, 2); ADD_ALL_TESTS(test_alpn, 2); ADD_ALL_TESTS(test_noisy_dgram, 2); + ADD_TEST(test_get_shutdown); return 1; err: -- Gitee From 53f318d0c574e2b98880d9eb88682c5b6434792e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 18 Oct 2023 10:01:21 -0400 Subject: [PATCH 30/67] Convert jdkTrustedKeyUsage to be a pkcs12 cmd line option Creating JDK compatible pkcs12 files requires a bit more than just adding the Trusted Key Usage OID to a certbag in the pkcs12 file. Additionally the JDK currently requires that pkcs12 files setting this oid _not_ contain any additional keys, and in response will produce unpredictable results. This could be solved by implying --nokeys when the pkcs12 utility is run and the config option is set, but thatcould confuse users who didn't specify nokeys on the command line. As such, remove the config file setting for this feature, and replace it with a -jdktrust command line option, that is documented to assert nokeys when a users specifies the new command line option. Fixes #22215 Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22422) Signed-off-by: fly2x --- apps/openssl-vms.cnf | 7 ----- apps/openssl.cnf | 7 ----- apps/pkcs12.c | 29 +++++++------------ doc/man1/openssl-pkcs12.pod.in | 10 +++++++ test/recipes/80-test_pkcs12.t | 3 +- .../80-test_pkcs12_data/jdk_trusted.cnf | 8 ----- 6 files changed, 22 insertions(+), 42 deletions(-) delete mode 100644 test/recipes/80-test_pkcs12_data/jdk_trusted.cnf diff --git a/apps/openssl-vms.cnf b/apps/openssl-vms.cnf index d6d5f58db6..8203d9ea0c 100644 --- a/apps/openssl-vms.cnf +++ b/apps/openssl-vms.cnf @@ -388,10 +388,3 @@ oldcert = $insta::certout # insta.cert.pem # Certificate revocation cmd = rr oldcert = $insta::certout # insta.cert.pem - -[pkcs12] -certBagAttr = cb_attr - -# Uncomment this if you need Java compatible PKCS12 files -[cb_attr] -#jdkTrustedKeyUsage = anyExtendedKeyUsage diff --git a/apps/openssl.cnf b/apps/openssl.cnf index 0d564d3ba5..2833b6f30b 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -388,10 +388,3 @@ oldcert = $insta::certout # insta.cert.pem # Certificate revocation cmd = rr oldcert = $insta::certout # insta.cert.pem - -[pkcs12] -certBagAttr = cb_attr - -# Uncomment this if you need Java compatible PKCS12 files -[cb_attr] -#jdkTrustedKeyUsage = anyExtendedKeyUsage diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 8e8c771819..1fa0abd3d4 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c @@ -71,7 +71,7 @@ typedef enum OPTION_choice { OPT_NAME, OPT_CSP, OPT_CANAME, OPT_IN, OPT_OUT, OPT_PASSIN, OPT_PASSOUT, OPT_PASSWORD, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_ENGINE, - OPT_R_ENUM, OPT_PROV_ENUM, + OPT_R_ENUM, OPT_PROV_ENUM, OPT_JDKTRUST, #ifndef OPENSSL_NO_DES OPT_LEGACY_ALG #endif @@ -154,6 +154,7 @@ const OPTIONS pkcs12_options[] = { {"maciter", OPT_MACITER, '-', "Unused, kept for backwards compatibility"}, {"macsaltlen", OPT_MACSALTLEN, 'p', "Specify the salt len for MAC"}, {"nomac", OPT_NOMAC, '-', "Don't generate MAC"}, + {"jdktrust", OPT_JDKTRUST, 's', "Mark certificate in PKCS#12 store as trusted for JDK compatibility"}, {NULL} }; @@ -165,6 +166,7 @@ int pkcs12_main(int argc, char **argv) char *name = NULL, *csp_name = NULL; char pass[PASSWD_BUF_SIZE] = "", macpass[PASSWD_BUF_SIZE] = ""; int export_pkcs12 = 0, options = 0, chain = 0, twopass = 0, keytype = 0; + char *jdktrust = NULL; #ifndef OPENSSL_NO_DES int use_legacy = 0; #endif @@ -222,6 +224,11 @@ int pkcs12_main(int argc, char **argv) case OPT_NOOUT: options |= (NOKEYS | NOCERTS); break; + case OPT_JDKTRUST: + jdktrust = opt_arg(); + /* Adding jdk trust implies nokeys */ + options |= NOKEYS; + break; case OPT_INFO: options |= INFO; break; @@ -530,9 +537,6 @@ int pkcs12_main(int argc, char **argv) int i; CONF *conf = NULL; ASN1_OBJECT *obj = NULL; - STACK_OF(CONF_VALUE) *cb_sk = NULL; - const char *cb_attr = NULL; - const CONF_VALUE *val = NULL; if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { BIO_printf(bio_err, "Nothing to export due to -noout or -nocerts and -nokeys\n"); @@ -682,20 +686,9 @@ int pkcs12_main(int argc, char **argv) goto export_end; if (!app_load_modules(conf)) goto export_end; - /* Find the cert bag section */ - cb_attr = app_conf_try_string(conf, "pkcs12", "certBagAttr"); - if (cb_attr != NULL) { - if ((cb_sk = NCONF_get_section(conf, cb_attr)) != NULL) { - for (i = 0; i < sk_CONF_VALUE_num(cb_sk); i++) { - val = sk_CONF_VALUE_value(cb_sk, i); - if (strcmp(val->name, "jdkTrustedKeyUsage") == 0) { - obj = OBJ_txt2obj(val->value, 0); - break; - } - } - } else { - ERR_clear_error(); - } + + if (jdktrust != NULL) { + obj = OBJ_txt2obj(jdktrust, 0); } p12 = PKCS12_create_ex2(cpass, name, key, ee_cert, certs, diff --git a/doc/man1/openssl-pkcs12.pod.in b/doc/man1/openssl-pkcs12.pod.in index 144650f742..665b22bb64 100644 --- a/doc/man1/openssl-pkcs12.pod.in +++ b/doc/man1/openssl-pkcs12.pod.in @@ -68,6 +68,7 @@ PKCS#12 output (export) options: [B<-maciter>] [B<-macsaltlen>] [B<-nomac>] +[B<-jdktrust> I] =head1 DESCRIPTION @@ -381,6 +382,15 @@ Do not attempt to provide the MAC integrity. This can be useful with the FIPS provider as the PKCS12 MAC requires PKCS12KDF which is not an approved FIPS algorithm and cannot be supported by the FIPS provider. +=item B<-jdktrust> + +Export pkcs12 file in a format compatible with Java keystore usage. This option +accepts a string parameter indicating the trust oid name to be granted to the +certificate it is associated with. Currently only "anyExtendedKeyUsage" is +defined. Note that, as Java keystores do not accept PKCS12 files with both +trusted certificates and keypairs, use of this option implies the setting of the +B<-nokeys> option + =back =head1 NOTES diff --git a/test/recipes/80-test_pkcs12.t b/test/recipes/80-test_pkcs12.t index 06a90ec24b..307942710f 100644 --- a/test/recipes/80-test_pkcs12.t +++ b/test/recipes/80-test_pkcs12.t @@ -172,9 +172,8 @@ ok(grep(/Trusted key usage (Oracle)/, @pkcs12info) == 0, # Test with Oracle Trusted Key Usage specified in openssl.cnf { - $ENV{OPENSSL_CONF} = srctop_file("test", "recipes", "80-test_pkcs12_data", "jdk_trusted.cnf"); ok(run(app(["openssl", "pkcs12", "-export", "-out", $outfile7, - "-in", srctop_file(@path, "ee-cert.pem"), + "-jdktrust", "anyExtendedKeyUsage", "-in", srctop_file(@path, "ee-cert.pem"), "-nokeys", "-passout", "pass:", "-certpbe", "NONE"])), "test nokeys single cert"); diff --git a/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf b/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf deleted file mode 100644 index 57d11fccf2..0000000000 --- a/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf +++ /dev/null @@ -1,8 +0,0 @@ -# -[pkcs12] -certBagAttr = cb_attr - -# Uncomment this if you need Java compatible PKCS12 files -[cb_attr] -jdkTrustedKeyUsage = anyExtendedKeyUsage - -- Gitee From 8043b3f9ecbbee751d8ae946985ab48452fd98fd Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Thu, 19 Oct 2023 09:27:11 +0100 Subject: [PATCH 31/67] QUIC: Prevent incoming oversize tokens Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22436) Signed-off-by: fly2x --- include/internal/quic_txp.h | 14 ++++---- ssl/quic/quic_channel.c | 14 ++++++-- ssl/quic/quic_txp.c | 62 +++++++++++++++++++++++++++++++++--- test/quic_multistream_test.c | 1 + test/quic_txp_test.c | 51 ++++++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 14 deletions(-) diff --git a/include/internal/quic_txp.h b/include/internal/quic_txp.h index 64efedc27f..ae508f2393 100644 --- a/include/internal/quic_txp.h +++ b/include/internal/quic_txp.h @@ -112,13 +112,15 @@ OSSL_TIME ossl_quic_tx_packetiser_get_deadline(OSSL_QUIC_TX_PACKETISER *txp); /* * Set the token used in Initial packets. The callback is called when the buffer * is no longer needed; for example, when the TXP is freed or when this function - * is called again with a new buffer. + * is called again with a new buffer. Fails returning 0 if the token is too big + * to ever be reasonably encapsulated in an outgoing packet based on our current + * understanding of our PMTU. */ -void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, - const unsigned char *token, - size_t token_len, - ossl_quic_initial_token_free_fn *free_cb, - void *free_cb_arg); +int ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, + const unsigned char *token, + size_t token_len, + ossl_quic_initial_token_free_fn *free_cb, + void *free_cb_arg); /* Change the DCID the TXP uses to send outgoing packets. */ int ossl_quic_tx_packetiser_set_cur_dcid(OSSL_QUIC_TX_PACKETISER *txp, diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 8e75eda539..9e5b841622 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2816,8 +2816,18 @@ static int ch_retry(QUIC_CHANNEL *ch, if ((buf = OPENSSL_memdup(retry_token, retry_token_len)) == NULL) return 0; - ossl_quic_tx_packetiser_set_initial_token(ch->txp, buf, retry_token_len, - free_token, NULL); + if (!ossl_quic_tx_packetiser_set_initial_token(ch->txp, buf, + retry_token_len, + free_token, NULL)) { + /* + * This may fail if the token we receive is too big for us to ever be + * able to transmit in an outgoing Initial packet. + */ + ossl_quic_channel_raise_protocol_error(ch, QUIC_ERR_INVALID_TOKEN, 0, + "received oversize token"); + OPENSSL_free(buf); + return 0; + } ch->retry_scid = *retry_scid; ch->doing_retry = 1; diff --git a/ssl/quic/quic_txp.c b/ssl/quic/quic_txp.c index 0f1e9b8f25..1045e79e0f 100644 --- a/ssl/quic/quic_txp.c +++ b/ssl/quic/quic_txp.c @@ -510,12 +510,63 @@ void ossl_quic_tx_packetiser_free(OSSL_QUIC_TX_PACKETISER *txp) OPENSSL_free(txp); } -void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, - const unsigned char *token, - size_t token_len, - ossl_quic_initial_token_free_fn *free_cb, - void *free_cb_arg) +/* + * Determine if an Initial packet token length is reasonable based on the + * current MDPL, returning 1 if it is OK. + * + * The real PMTU to the peer could differ from our (pessimistic) understanding + * of the PMTU, therefore it is possible we could receive an Initial token from + * a server in a Retry packet which is bigger than the MDPL. In this case it is + * impossible for us ever to make forward progress and we need to error out + * and fail the connection attempt. + * + * The specific boundary condition is complex: for example, after the size of + * the Initial token, there are the Initial packet header overheads and then + * encryption/AEAD tag overheads. After that, the minimum room for frame data in + * order to guarantee forward progress must be guaranteed. For example, a crypto + * stream needs to always be able to serialize at least one byte in a CRYPTO + * frame in order to make forward progress. Because the offset field of a CRYPTO + * frame uses a variable-length integer, the number of bytes needed to ensure + * this also varies. + * + * Rather than trying to get this boundary condition check actually right, + * require a reasonable amount of slack to avoid pathological behaviours. (After + * all, transmitting a CRYPTO stream one byte at a time is probably not + * desirable anyway.) + * + * We choose 160 bytes as the required margin, which is double the rough + * estimation of the minimum we would require to guarantee forward progress + * under worst case packet overheads. + */ +#define TXP_REQUIRED_TOKEN_MARGIN 160 + +static int txp_check_token_len(size_t token_len, size_t mdpl) +{ + if (token_len == 0) + return 1; + + if (token_len >= mdpl) + return 0; + + if (TXP_REQUIRED_TOKEN_MARGIN >= mdpl) + /* (should not be possible because MDPL must be at least 1200) */ + return 0; + + if (token_len > mdpl - TXP_REQUIRED_TOKEN_MARGIN) + return 0; + + return 1; +} + +int ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, + const unsigned char *token, + size_t token_len, + ossl_quic_initial_token_free_fn *free_cb, + void *free_cb_arg) { + if (!txp_check_token_len(token_len, txp_get_mdpl(txp))) + return 0; + if (txp->initial_token != NULL && txp->initial_token_free_cb != NULL) txp->initial_token_free_cb(txp->initial_token, txp->initial_token_len, txp->initial_token_free_cb_arg); @@ -524,6 +575,7 @@ void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, txp->initial_token_len = token_len; txp->initial_token_free_cb = free_cb; txp->initial_token_free_cb_arg = free_cb_arg; + return 1; } int ossl_quic_tx_packetiser_set_cur_dcid(OSSL_QUIC_TX_PACKETISER *txp, diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index e4663ece17..958dd30fc1 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -4902,6 +4902,7 @@ static const struct script_op script_76[] = { OP_END }; +/* 77. Ensure default stream popping operates correctly */ static const struct script_op script_77[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () diff --git a/test/quic_txp_test.c b/test/quic_txp_test.c index 4682483acc..423d28ddcb 100644 --- a/test/quic_txp_test.c +++ b/test/quic_txp_test.c @@ -1198,6 +1198,54 @@ static const struct script_op script_17[] = { OP_END }; +/* 18. Big Token Rejection */ +static const unsigned char big_token[1950]; + +static int try_big_token(struct helper *h) +{ + size_t i; + + /* Ensure big token is rejected */ + if (!TEST_false(ossl_quic_tx_packetiser_set_initial_token(h->txp, + big_token, + sizeof(big_token), + NULL, + NULL))) + return 0; + + /* + * Keep trying until we find an acceptable size, then make sure + * that works for generation + */ + for (i = sizeof(big_token) - 1;; --i) { + if (!TEST_size_t_gt(i, 0)) + return 0; + + if (ossl_quic_tx_packetiser_set_initial_token(h->txp, big_token, i, + NULL, NULL)) + break; + } + + return 1; +} + +static const struct script_op script_18[] = { + OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_INITIAL, QRL_SUITE_AES128GCM, secret_1) + OP_TXP_GENERATE_NONE() + OP_CHECK(try_big_token) + OP_TXP_GENERATE_NONE() + OP_CRYPTO_SEND(QUIC_PN_SPACE_INITIAL, crypto_1) + OP_TXP_GENERATE() + OP_RX_PKT() + OP_EXPECT_DGRAM_LEN(1200, 1200) + OP_NEXT_FRAME() + OP_EXPECT_FRAME(OSSL_QUIC_FRAME_TYPE_CRYPTO) + OP_EXPECT_NO_FRAME() + OP_RX_PKT_NONE() + OP_TXP_GENERATE_NONE() + OP_END +}; + static const struct script_op *const scripts[] = { script_1, script_2, @@ -1215,7 +1263,8 @@ static const struct script_op *const scripts[] = { script_14, script_15, script_16, - script_17 + script_17, + script_18 }; static void skip_padding(struct helper *h) -- Gitee From 6b77b7bab28269345e602dad02b4352b9a27f430 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Thu, 19 Oct 2023 11:58:26 +0100 Subject: [PATCH 32/67] QUIC: Test handling of post-connection session tickets Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22439) Signed-off-by: fly2x --- test/quic_multistream_test.c | 63 +++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index 958dd30fc1..36be2dc80c 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -4923,6 +4923,66 @@ static const struct script_op script_77[] = { OP_END }; +/* 78. Post-connection session ticket handling */ +static size_t new_session_count; + +static int on_new_session(SSL *s, SSL_SESSION *sess) +{ + ++new_session_count; + return 0; /* do not ref session, we aren't keeping it */ +} + +static int setup_session(struct helper *h, struct helper_local *hl) +{ + SSL_CTX_set_session_cache_mode(h->c_ctx, SSL_SESS_CACHE_BOTH); + SSL_CTX_sess_set_new_cb(h->c_ctx, on_new_session); + return 1; +} + +static int trigger_late_session_ticket(struct helper *h, struct helper_local *hl) +{ + new_session_count = 0; + + if (!TEST_true(ossl_quic_tserver_new_ticket(ACQUIRE_S()))) + return 0; + + return 1; +} + +static int check_got_session_ticket(struct helper *h, struct helper_local *hl) +{ + if (!TEST_size_t_gt(new_session_count, 0)) + return 0; + + return 1; +} + +static const struct script_op script_78[] = { + OP_C_SET_ALPN ("ossltest") + OP_CHECK (setup_session, 0) + OP_C_CONNECT_WAIT () + + OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) + + OP_C_NEW_STREAM_BIDI (a, C_BIDI_ID(0)) + OP_C_WRITE (a, "apple", 5) + + OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) + OP_S_READ_EXPECT (a, "apple", 5) + + OP_S_WRITE (a, "orange", 6) + OP_C_READ_EXPECT (a, "orange", 6) + + OP_CHECK (trigger_late_session_ticket, 0) + + OP_S_WRITE (a, "Strawberry", 10) + OP_C_READ_EXPECT (a, "Strawberry", 10) + + OP_CHECK (check_got_session_ticket, 0) + + OP_END +}; + static const struct script_op *const scripts[] = { script_1, script_2, @@ -5000,7 +5060,8 @@ static const struct script_op *const scripts[] = { script_74, script_75, script_76, - script_77 + script_77, + script_78 }; static int test_script(int idx) -- Gitee From 9c93136b8c4f4636e3044b1b3ed151b4eefa5d40 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 19 Oct 2023 11:00:39 +0100 Subject: [PATCH 33/67] Round up nano secs when converting OSSL_TIME to struct timeval struct timeval doesn't support nanosecs but OSSL_TIME does. We round up any nanosecs to ensure that a non-zero input always results in a non-zero output. This fixes a quic-client fuzzer hang. Fixes #22437 Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22440) Signed-off-by: fly2x --- include/internal/time.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/include/internal/time.h b/include/internal/time.h index 9bc5e54512..14d724abf5 100644 --- a/include/internal/time.h +++ b/include/internal/time.h @@ -45,6 +45,13 @@ typedef struct { #define ossl_us2time(us) ossl_ticks2time((us) * OSSL_TIME_US) #define ossl_time2us(t) (ossl_time2ticks(t) / OSSL_TIME_US) +/* + * Arithmetic operations on times. + * These operations are saturating, in that an overflow or underflow returns + * the largest or smallest value respectively. + */ +OSSL_SAFE_MATH_UNSIGNED(time, uint64_t) + /* Convert a tick count into a time */ static ossl_unused ossl_inline OSSL_TIME ossl_ticks2time(uint64_t ticks) @@ -84,6 +91,15 @@ static ossl_unused ossl_inline struct timeval ossl_time_to_timeval(OSSL_TIME t) { struct timeval tv; + int err = 0; + + /* + * Round up any nano secs which struct timeval doesn't support. Ensures that + * we never return a zero time if the input time is non zero + */ + t.t = safe_add_time(t.t, OSSL_TIME_US - 1, &err); + if (err) + t = ossl_time_infinite(); #ifdef _WIN32 tv.tv_sec = (long int)(t.t / OSSL_TIME_SECOND); @@ -151,13 +167,6 @@ int ossl_time_is_infinite(OSSL_TIME t) return ossl_time_compare(t, ossl_time_infinite()) == 0; } -/* - * Arithmetic operations on times. - * These operations are saturating, in that an overflow or underflow returns - * the largest or smallest value respectively. - */ -OSSL_SAFE_MATH_UNSIGNED(time, uint64_t) - static ossl_unused ossl_inline OSSL_TIME ossl_time_add(OSSL_TIME a, OSSL_TIME b) { -- Gitee From 4fc02c96f8c38d15cefd3b6da4509b803f9eafac Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 19 Oct 2023 11:37:28 +0100 Subject: [PATCH 34/67] Add a test for converting OSSL_TIME to struct timeval Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22440) Signed-off-by: fly2x --- test/build.info | 6 ++- test/recipes/02-test_time.t | 12 ++++++ test/time_test.c | 79 +++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 test/recipes/02-test_time.t create mode 100644 test/time_test.c diff --git a/test/build.info b/test/build.info index 73f8de1f7a..cd8254164a 100644 --- a/test/build.info +++ b/test/build.info @@ -34,7 +34,7 @@ IF[{- !$disabled{tests} -}] confdump \ versions \ aborttest test_test pkcs12_format_test pkcs12_api_test \ - sanitytest rsa_complex exdatatest bntest \ + sanitytest time_test rsa_complex exdatatest bntest \ ecstresstest gmdifftest pbelutest \ destest mdc2test sha_test \ exptest pbetest localetest evp_pkey_ctx_new_from_name \ @@ -97,6 +97,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[sanitytest]=../include ../apps/include DEPEND[sanitytest]=../libcrypto.a libtestutil.a + SOURCE[time_test]=time_test.c + INCLUDE[time_test]=../include ../apps/include + DEPEND[time_test]=../libcrypto.a libtestutil.a + SOURCE[rand_test]=rand_test.c INCLUDE[rand_test]=../include ../apps/include DEPEND[rand_test]=../libcrypto libtestutil.a diff --git a/test/recipes/02-test_time.t b/test/recipes/02-test_time.t new file mode 100644 index 0000000000..c4534034fc --- /dev/null +++ b/test/recipes/02-test_time.t @@ -0,0 +1,12 @@ +#! /usr/bin/env perl +# Copyright 2023 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 + + +use OpenSSL::Test::Simple; + +simple_test("test_time", "time_test"); diff --git a/test/time_test.c b/test/time_test.c new file mode 100644 index 0000000000..62f911f61c --- /dev/null +++ b/test/time_test.c @@ -0,0 +1,79 @@ +/* + * Copyright 2023 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 "testutil.h" +#include "internal/time.h" + +static int test_time_to_timeval(void) +{ + OSSL_TIME a; + struct timeval tv; + + a = ossl_time_zero(); + + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + + /* Test that zero round trips */ + if (!TEST_true(ossl_time_is_zero(ossl_time_from_timeval(tv)))) + return 0; + + /* We should round up nano secs to the next usec */ + a = ossl_ticks2time(1); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + a = ossl_ticks2time(999); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + a = ossl_ticks2time(1000); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + a = ossl_ticks2time(1001); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 2)) + return 0; + a = ossl_ticks2time(999000); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 999)) + return 0; + a = ossl_ticks2time(999999001); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + a = ossl_ticks2time(999999999); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + a = ossl_ticks2time(1000000000); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + a = ossl_ticks2time(1000000001); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + + /* + * Note that we don't currently support infinity round tripping. Instead + * callers need to explicitly test for infinity. + */ + + return 1; +} + +int setup_tests(void) +{ + ADD_TEST(test_time_to_timeval); + + return 1; +} -- Gitee From e73e55f9cbe92eafc91e273a02b77a5b57d864e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 18 Oct 2023 15:35:55 +0200 Subject: [PATCH 35/67] Reference the non-"legacy" provider names directly from EVP_md5(3) &c. Earlier today, it took me five manuals! to find what on earth the "Performance"/"EVP_MD_fetch(3)" crosslinks actually mean: EVP_sha1(3) crypto(7) EVP_MD_fetch(3) (but not there! don't read that!) OSSL_PROVIDER-default(7) EVP_MD-SHA1(7) If, instead, EVP_sha1(3) referenced EVP_MD-SHA1(7) at /all/, which it should do, since it's supposed to be what you're replacing it with, but it doesn't actually say that, maybe people would use it. I know I didn't because it's basically just deadass buried As found by git grep -l 'and should consider using' Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22420) Signed-off-by: fly2x --- doc/man3/EVP_aes_128_gcm.pod | 2 +- doc/man3/EVP_aria_128_gcm.pod | 2 +- doc/man3/EVP_bf_cbc.pod | 2 +- doc/man3/EVP_blake2b512.pod | 2 +- doc/man3/EVP_camellia_128_ecb.pod | 2 +- doc/man3/EVP_cast5_cbc.pod | 2 +- doc/man3/EVP_chacha20.pod | 2 +- doc/man3/EVP_des_cbc.pod | 2 +- doc/man3/EVP_desx_cbc.pod | 2 +- doc/man3/EVP_idea_cbc.pod | 2 +- doc/man3/EVP_md2.pod | 2 +- doc/man3/EVP_md4.pod | 2 +- doc/man3/EVP_md5.pod | 2 +- doc/man3/EVP_mdc2.pod | 2 +- doc/man3/EVP_rc2_cbc.pod | 2 +- doc/man3/EVP_rc4.pod | 2 +- doc/man3/EVP_rc5_32_12_16_cbc.pod | 2 +- doc/man3/EVP_ripemd160.pod | 2 +- doc/man3/EVP_seed_cbc.pod | 2 +- doc/man3/EVP_sha1.pod | 2 +- doc/man3/EVP_sha224.pod | 2 +- doc/man3/EVP_sha3_224.pod | 2 +- doc/man3/EVP_sm3.pod | 2 +- doc/man3/EVP_sm4_cbc.pod | 2 +- doc/man3/EVP_whirlpool.pod | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/doc/man3/EVP_aes_128_gcm.pod b/doc/man3/EVP_aes_128_gcm.pod index 067f17e8fc..485705ea78 100644 --- a/doc/man3/EVP_aes_128_gcm.pod +++ b/doc/man3/EVP_aes_128_gcm.pod @@ -167,7 +167,7 @@ the XTS "tweak" value. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_aria_128_gcm.pod b/doc/man3/EVP_aria_128_gcm.pod index 9291365263..91aa75ec38 100644 --- a/doc/man3/EVP_aria_128_gcm.pod +++ b/doc/man3/EVP_aria_128_gcm.pod @@ -96,7 +96,7 @@ correctly, see the L section for details. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_bf_cbc.pod b/doc/man3/EVP_bf_cbc.pod index 4df98f4bdf..11a909207a 100644 --- a/doc/man3/EVP_bf_cbc.pod +++ b/doc/man3/EVP_bf_cbc.pod @@ -41,7 +41,7 @@ Blowfish encryption algorithm in CBC, CFB, ECB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_blake2b512.pod b/doc/man3/EVP_blake2b512.pod index 98e1899f6a..55bd9f3bce 100644 --- a/doc/man3/EVP_blake2b512.pod +++ b/doc/man3/EVP_blake2b512.pod @@ -35,7 +35,7 @@ The BLAKE2b algorithm that produces a 512-bit output from a given input. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. While the BLAKE2b and BLAKE2s algorithms supports a variable length digest, diff --git a/doc/man3/EVP_camellia_128_ecb.pod b/doc/man3/EVP_camellia_128_ecb.pod index a6b597156a..cb6e12e212 100644 --- a/doc/man3/EVP_camellia_128_ecb.pod +++ b/doc/man3/EVP_camellia_128_ecb.pod @@ -79,7 +79,7 @@ Camellia for 128, 192 and 256 bit keys in the following modes: CBC, CFB with Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_cast5_cbc.pod b/doc/man3/EVP_cast5_cbc.pod index 85ff2ad014..7fef059815 100644 --- a/doc/man3/EVP_cast5_cbc.pod +++ b/doc/man3/EVP_cast5_cbc.pod @@ -41,7 +41,7 @@ CAST encryption algorithm in CBC, ECB, CFB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_chacha20.pod b/doc/man3/EVP_chacha20.pod index 683faa326e..7e80c8de40 100644 --- a/doc/man3/EVP_chacha20.pod +++ b/doc/man3/EVP_chacha20.pod @@ -44,7 +44,7 @@ L section for more information. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. L diff --git a/doc/man3/EVP_des_cbc.pod b/doc/man3/EVP_des_cbc.pod index 501216cd6d..442be8993a 100644 --- a/doc/man3/EVP_des_cbc.pod +++ b/doc/man3/EVP_des_cbc.pod @@ -89,7 +89,7 @@ Triple-DES key wrap according to RFC 3217 Section 3. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_desx_cbc.pod b/doc/man3/EVP_desx_cbc.pod index fae827192e..c22c0de479 100644 --- a/doc/man3/EVP_desx_cbc.pod +++ b/doc/man3/EVP_desx_cbc.pod @@ -31,7 +31,7 @@ implementation. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_idea_cbc.pod b/doc/man3/EVP_idea_cbc.pod index 5a9adaedc4..a36aae0bc9 100644 --- a/doc/man3/EVP_idea_cbc.pod +++ b/doc/man3/EVP_idea_cbc.pod @@ -39,7 +39,7 @@ The IDEA encryption algorithm in CBC, CFB, ECB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_md2.pod b/doc/man3/EVP_md2.pod index 0b473887e0..a6f3a010de 100644 --- a/doc/man3/EVP_md2.pod +++ b/doc/man3/EVP_md2.pod @@ -28,7 +28,7 @@ The MD2 algorithm which produces a 128-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_md4.pod b/doc/man3/EVP_md4.pod index baaff9e4ea..a4e1a7d0a6 100644 --- a/doc/man3/EVP_md4.pod +++ b/doc/man3/EVP_md4.pod @@ -29,7 +29,7 @@ The MD4 algorithm which produces a 128-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_md5.pod b/doc/man3/EVP_md5.pod index 752fdd1f6c..42370fb3d0 100644 --- a/doc/man3/EVP_md5.pod +++ b/doc/man3/EVP_md5.pod @@ -40,7 +40,7 @@ WARNING: this algorithm is not intended for non-SSL usage. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L or L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_mdc2.pod b/doc/man3/EVP_mdc2.pod index e9de6f3c56..3681bd06a6 100644 --- a/doc/man3/EVP_mdc2.pod +++ b/doc/man3/EVP_mdc2.pod @@ -30,7 +30,7 @@ The MDC-2DES algorithm of using MDC-2 with the DES block cipher. It produces a Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_rc2_cbc.pod b/doc/man3/EVP_rc2_cbc.pod index bf4a13ba45..17f6f4b3e2 100644 --- a/doc/man3/EVP_rc2_cbc.pod +++ b/doc/man3/EVP_rc2_cbc.pod @@ -55,7 +55,7 @@ functions to set the key length and effective key length. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_rc4.pod b/doc/man3/EVP_rc4.pod index f22e88a652..0311ef278c 100644 --- a/doc/man3/EVP_rc4.pod +++ b/doc/man3/EVP_rc4.pod @@ -47,7 +47,7 @@ interface. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_rc5_32_12_16_cbc.pod b/doc/man3/EVP_rc5_32_12_16_cbc.pod index c177b18451..69fc2f2cc6 100644 --- a/doc/man3/EVP_rc5_32_12_16_cbc.pod +++ b/doc/man3/EVP_rc5_32_12_16_cbc.pod @@ -60,7 +60,7 @@ is an int. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_ripemd160.pod b/doc/man3/EVP_ripemd160.pod index 6ad2d3e018..5b96fd09f8 100644 --- a/doc/man3/EVP_ripemd160.pod +++ b/doc/man3/EVP_ripemd160.pod @@ -29,7 +29,7 @@ The RIPEMD-160 algorithm which produces a 160-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_seed_cbc.pod b/doc/man3/EVP_seed_cbc.pod index 010607e574..2c821d07c3 100644 --- a/doc/man3/EVP_seed_cbc.pod +++ b/doc/man3/EVP_seed_cbc.pod @@ -41,7 +41,7 @@ The SEED encryption algorithm in CBC, CFB, ECB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sha1.pod b/doc/man3/EVP_sha1.pod index 264ddd1add..6fc8f07b06 100644 --- a/doc/man3/EVP_sha1.pod +++ b/doc/man3/EVP_sha1.pod @@ -29,7 +29,7 @@ The SHA-1 algorithm which produces a 160-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sha224.pod b/doc/man3/EVP_sha224.pod index 7a50cf9b6c..be09e49ee3 100644 --- a/doc/man3/EVP_sha224.pod +++ b/doc/man3/EVP_sha224.pod @@ -49,7 +49,7 @@ their outputs are of the same size. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with Linstead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sha3_224.pod b/doc/man3/EVP_sha3_224.pod index 5bb9ae1b89..93c0d0b9fb 100644 --- a/doc/man3/EVP_sha3_224.pod +++ b/doc/man3/EVP_sha3_224.pod @@ -54,7 +54,7 @@ B provides that of 256 bits. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L or L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sm3.pod b/doc/man3/EVP_sm3.pod index 4e8112dc0a..65be55e88d 100644 --- a/doc/man3/EVP_sm3.pod +++ b/doc/man3/EVP_sm3.pod @@ -28,7 +28,7 @@ The SM3 hash function. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sm4_cbc.pod b/doc/man3/EVP_sm4_cbc.pod index b67ade5499..48be7a31ad 100644 --- a/doc/man3/EVP_sm4_cbc.pod +++ b/doc/man3/EVP_sm4_cbc.pod @@ -45,7 +45,7 @@ respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_whirlpool.pod b/doc/man3/EVP_whirlpool.pod index a9826e290a..c5d465b16f 100644 --- a/doc/man3/EVP_whirlpool.pod +++ b/doc/man3/EVP_whirlpool.pod @@ -30,7 +30,7 @@ input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES -- Gitee From 0a88bafab44f9acf68015d189781e5a0b0d11e62 Mon Sep 17 00:00:00 2001 From: Kurt Roeckx Date: Wed, 23 Nov 2022 14:24:13 +0100 Subject: [PATCH 36/67] Add quic client fuzzer. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- fuzz/build.info | 16 ++++++ fuzz/quic-client.c | 139 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 fuzz/quic-client.c diff --git a/fuzz/build.info b/fuzz/build.info index 7efc52ef85..a068c2f230 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -29,6 +29,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] PROGRAMS{noinst}=x509 ENDIF + IF[{- !$disabled{"quic"} -}] + PROGRAMS{noinst}=quic-client + ENDIF + SOURCE[asn1]=asn1.c driver.c fuzz_rand.c INCLUDE[asn1]=../include {- $ex_inc -} DEPEND[asn1]=../libcrypto ../libssl {- $ex_lib -} @@ -89,6 +93,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] INCLUDE[v3name]=../include {- $ex_inc -} DEPEND[v3name]=../libcrypto.a {- $ex_lib -} + SOURCE[quic-client]=quic-client.c driver.c fuzz_rand.c + INCLUDE[quic-client]=../include {- $ex_inc -} + DEPEND[quic-client]=../libcrypto ../libssl {- $ex_lib -} + SOURCE[server]=server.c driver.c fuzz_rand.c INCLUDE[server]=../include {- $ex_inc -} DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} @@ -119,6 +127,10 @@ IF[{- !$disabled{tests} -}] PROGRAMS{noinst}=x509-test ENDIF + IF[{- !$disabled{"quic"} -}] + PROGRAMS{noinst}=quic-client-test + ENDIF + SOURCE[asn1-test]=asn1.c test-corpus.c fuzz_rand.c INCLUDE[asn1-test]=../include DEPEND[asn1-test]=../libcrypto ../libssl @@ -180,6 +192,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[v3name-test]=../include DEPEND[v3name-test]=../libcrypto.a + SOURCE[quic-client-test]=quic-client.c test-corpus.c fuzz_rand.c + INCLUDE[quic-client-test]=../include + DEPEND[quic-client-test]=../libcrypto ../libssl + SOURCE[server-test]=server.c test-corpus.c fuzz_rand.c INCLUDE[server-test]=../include DEPEND[server-test]=../libcrypto ../libssl diff --git a/fuzz/quic-client.c b/fuzz/quic-client.c new file mode 100644 index 0000000000..c172372af3 --- /dev/null +++ b/fuzz/quic-client.c @@ -0,0 +1,139 @@ +/* + * Copyright 2016-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 may obtain a copy of the License at + * https://www.openssl.org/source/license.html + * or in the file LICENSE in the source distribution. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "fuzzer.h" +#include "internal/sockets.h" + +/* unused, to avoid warning. */ +static int idx; + +#define FUZZTIME 1485898104 + +#define TIME_IMPL(t) { if (t != NULL) *t = FUZZTIME; return FUZZTIME; } + +/* + * This might not work in all cases (and definitely not on Windows + * because of the way linkers are) and callees can still get the + * current time instead of the fixed time. This will just result + * in things not being fully reproducible and have a slightly + * different coverage. + */ +#if !defined(_WIN32) +time_t time(time_t *t) TIME_IMPL(t) +#endif + +int FuzzerInitialize(int *argc, char ***argv) +{ + STACK_OF(SSL_COMP) *comp_methods; + + FuzzerSetRand(); + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL); + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + ERR_clear_error(); + CRYPTO_free_ex_index(0, -1); + idx = SSL_get_ex_data_X509_STORE_CTX_idx(); + comp_methods = SSL_COMP_get_compression_methods(); + if (comp_methods != NULL) + sk_SSL_COMP_sort(comp_methods); + + return 1; +} + +int FuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + SSL *client = NULL; + BIO *in; + BIO *out; + SSL_CTX *ctx; + BIO_ADDR *peer_addr = NULL; + struct in_addr ina = {0}; + + if (len == 0) + return 0; + + /* This only fuzzes the initial flow from the client so far. */ + ctx = SSL_CTX_new(OSSL_QUIC_client_method()); + if (ctx == NULL) + goto end; + + client = SSL_new(ctx); + if (client == NULL) + goto end; + + peer_addr = BIO_ADDR_new(); + if (peer_addr == NULL) + goto end; + + ina.s_addr = htonl(0x7f000001UL); + + if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), + htons(4433))) + goto end; + + /* + OPENSSL_assert(SSL_set_min_proto_version(client, 0) == 1); + OPENSSL_assert(SSL_set_cipher_list(client, "ALL:eNULL:@SECLEVEL=0") == 1); + */ + SSL_set_tlsext_host_name(client, "localhost"); + in = BIO_new(BIO_s_dgram_mem()); + if (in == NULL) + goto end; + out = BIO_new(BIO_s_dgram_mem()); + if (out == NULL) { + BIO_free(in); + goto end; + } + if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08quicfuzz", 9) != 0) + goto end; + SSL_set_bio(client, in, out); + if (SSL_set1_initial_peer_addr(client, peer_addr) != 1) + goto end; + SSL_set_connect_state(client); + while (len > 3) + { + size_t size = buf[0] + (buf[1] << 8); + + if (size > len - 2) + break; + + if (size > 0) + /* OPENSSL_assert((size_t)BIO_write(in, buf+2, size) == size); */ + BIO_write(in, buf+2, size); + len -= size + 2; + buf += size + 2; + + if (SSL_do_handshake(client) == 1) { + /* Keep reading application data until error or EOF. */ + uint8_t tmp[1024]; + if (SSL_read(client, tmp, sizeof(tmp)) <= 0) + break; + } + } + end: + SSL_free(client); + ERR_clear_error(); + SSL_CTX_free(ctx); + BIO_ADDR_free(peer_addr); + + return 0; +} + +void FuzzerCleanup(void) +{ + FuzzerClearRand(); +} -- Gitee From 9d8652fbe9ff441231c2199f7547910505092541 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 6 Oct 2023 17:32:14 +0100 Subject: [PATCH 37/67] Don't encrypt/decrypt packet data during fuzzing Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- ssl/quic/quic_record_rx.c | 13 +++++++++++++ ssl/quic/quic_record_tx.c | 5 +++++ ssl/quic/quic_wire_pkt.c | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index 31c1f8fffd..6756ddb151 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -757,12 +757,25 @@ static int qrx_decrypt_pkt_body(OSSL_QRX *qrx, unsigned char *dst, if (EVP_CipherUpdate(cctx, dst, &l, src, src_len - el->tag_len) != 1) return 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* + * Throw away what we just decrypted and just use the ciphertext instead + * (which should be unencrypted) + */ + memcpy(dst, src, l); + + /* Pretend to authenticate the tag but ignore it */ + if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) { + /* We don't care */ + } +#else /* Ensure authentication succeeded. */ if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) { /* Authentication failed, increment failed auth counter. */ ++qrx->forged_pkt_count; return 0; } +#endif *dec_len = l; return 1; diff --git a/ssl/quic/quic_record_tx.c b/ssl/quic/quic_record_tx.c index d450470366..4f86c68e17 100644 --- a/ssl/quic/quic_record_tx.c +++ b/ssl/quic/quic_record_tx.c @@ -543,6 +543,11 @@ static int qtx_encrypt_into_txe(OSSL_QTX *qtx, struct iovec_cur *cur, TXE *txe, return 0; } +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Ignore what we just encrypted and overwrite it with the plaintext */ + memcpy(txe_data(txe) + txe->data_len, src, l); +#endif + assert(l > 0 && src_len == (size_t)l); txe->data_len += src_len; } diff --git a/ssl/quic/quic_wire_pkt.c b/ssl/quic/quic_wire_pkt.c index 136c40e7ad..acb926ad38 100644 --- a/ssl/quic/quic_wire_pkt.c +++ b/ssl/quic/quic_wire_pkt.c @@ -115,6 +115,11 @@ static int hdr_generate_mask(QUIC_HDR_PROTECTOR *hpr, return 0; } +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* No matter what we did above we use the same mask in fuzzing mode */ + memset(mask, 0, 5); +#endif + return 1; } -- Gitee From 9319f710fb1d38e0624f6a99e8212a057e3639c3 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 11 Oct 2023 10:43:58 +0100 Subject: [PATCH 38/67] Updates to the quic client fuzzer Handle retryable errors from SSL_read(). Also ensure the underlying BIO handles the destination address capability. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- fuzz/quic-client.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/fuzz/quic-client.c b/fuzz/quic-client.c index c172372af3..548ed7ec32 100644 --- a/fuzz/quic-client.c +++ b/fuzz/quic-client.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "fuzzer.h" #include "internal/sockets.h" @@ -98,9 +99,14 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) BIO_free(in); goto end; } - if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08quicfuzz", 9) != 0) + if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) { + BIO_free(in); + BIO_free(out); goto end; + } SSL_set_bio(client, in, out); + if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0) + goto end; if (SSL_set1_initial_peer_addr(client, peer_addr) != 1) goto end; SSL_set_connect_state(client); @@ -118,10 +124,23 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) buf += size + 2; if (SSL_do_handshake(client) == 1) { - /* Keep reading application data until error or EOF. */ + /* + * Keep reading application data until there are no more datagrams + * to inject or a fatal error occurs + */ uint8_t tmp[1024]; - if (SSL_read(client, tmp, sizeof(tmp)) <= 0) - break; + int ret; + + ret = SSL_read(client, tmp, sizeof(tmp)); + if (ret <= 0) { + switch (SSL_get_error(client, ret)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + break; + default: + goto end; + } + } } } end: -- Gitee From 51b138f6ae482bec123a75486d6d229438a42cae Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 11 Oct 2023 10:45:14 +0100 Subject: [PATCH 39/67] Don't fail on a bad dcid in the tranport params when fuzzing We accept a bad original destination connection id in the transport params while we are fuzzing since this may change every time. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- ssl/quic/quic_channel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 9e5b841622..ef6ad15087 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -1311,11 +1311,13 @@ static int ch_on_transport_params(const unsigned char *params, goto malformed; } +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Must match our initial DCID. */ if (!ossl_quic_conn_id_eq(&ch->init_dcid, &cid)) { reason = TP_REASON_EXPECTED_VALUE("ORIG_DCID"); goto malformed; } +#endif got_orig_dcid = 1; break; -- Gitee From 686f843dad8286dbed753748461bb5e88ba4d191 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 11 Oct 2023 10:46:46 +0100 Subject: [PATCH 40/67] Ignore a bad signature in a CertificateVerify message while fuzzing We ignore such a bad signature when fuzzing - it will never be correct. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- ssl/statem/statem_lib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index d979b6d5fc..5693a1269d 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -575,6 +575,11 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL_CONNECTION *s, PACKET *pkt) } } else { j = EVP_DigestVerify(mctx, data, len, hdata, hdatalen); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Ignore bad signatures when fuzzing */ + if (SSL_IS_QUIC_HANDSHAKE(s)) + j = 1; +#endif if (j <= 0) { SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_R_BAD_SIGNATURE); goto err; -- Gitee From 41291c3363c1d618a79ad7f3b14a0ae09a1c6045 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 11 Oct 2023 17:35:10 +0100 Subject: [PATCH 41/67] Update the fuzz README to provide info about the stdc++ requirements Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- fuzz/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fuzz/README.md b/fuzz/README.md index 6cc7811ad0..795606fec2 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -32,6 +32,34 @@ to the `libFuzzer` library file while configuring; this is represented as enable-ssl3 enable-ssl3-method enable-nextprotoneg \ --debug +Clang uses the gcc libstdc++ library so this must also be installed. You can +check which version of gcc clang is using like this: + + $ clang --verbose + Ubuntu clang version 14.0.0-1ubuntu1.1 + Target: x86_64-pc-linux-gnu + Thread model: posix + InstalledDir: /usr/bin + Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/12 + Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10 + Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11 + Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 + Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 + Candidate multilib: .;@m64 + Selected multilib: .;@m64 + +So, in the above example clang is using gcc version 12. Ensure that the selected +gcc version has the relevant libstdc++ files installed: + + $ ls /usr/lib/gcc/x86_64-linux-gnu/12 | grep stdc++ + libstdc++.a + libstdc++fs.a + libstdc++.so + +On Ubuntu for gcc-12 this requires the libstdc++-12-dev package installed. + + $ sudo apt-get install libstdc++-12-dev + Compile: sudo apt-get install make -- Gitee From 1dafb9336693daee5482aa3ed7aa0ce114b1af1e Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 11 Oct 2023 17:35:33 +0100 Subject: [PATCH 42/67] Add fuzz test recipe for the quic client fuzzer Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- test/recipes/99-test_fuzz_quic_client.t | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/recipes/99-test_fuzz_quic_client.t diff --git a/test/recipes/99-test_fuzz_quic_client.t b/test/recipes/99-test_fuzz_quic_client.t new file mode 100644 index 0000000000..2a2849035a --- /dev/null +++ b/test/recipes/99-test_fuzz_quic_client.t @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +# Copyright 2016-2020 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 + +use strict; +use warnings; + +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test::Utils; + +my $fuzzer = "quic-client"; +setup("test_fuzz_${fuzzer}"); + +plan tests => 2; # one more due to below require_ok(...) + +require_ok(srctop_file('test','recipes','fuzz.pl')); + +fuzz_ok($fuzzer); -- Gitee From 82259a48723bfe80935af71a0523072c2b4a9fdf Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Oct 2023 12:38:22 +0100 Subject: [PATCH 43/67] Ensure that the ERR_STATE is left in a consistent state We shouldn't ever have the case where the data flags indicate that err_data has been malloc'd, but the err_data field is NULL. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- crypto/err/err.c | 3 ++- crypto/err/err_save.c | 16 +++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crypto/err/err.c b/crypto/err/err.c index 7b7f309951..b95182d702 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -834,7 +834,8 @@ void ERR_add_error_vdata(int num, va_list args) * If err_data is allocated already, reuse the space. * Otherwise, allocate a small new buffer. */ - if ((es->err_data_flags[i] & flags) == flags) { + if ((es->err_data_flags[i] & flags) == flags + && ossl_assert(es->err_data[i] != NULL)) { str = es->err_data[i]; size = es->err_data_size[i]; diff --git a/crypto/err/err_save.c b/crypto/err/err_save.c index 3ca059adc3..1994c26cee 100644 --- a/crypto/err/err_save.c +++ b/crypto/err/err_save.c @@ -85,16 +85,18 @@ void OSSL_ERR_STATE_save_to_mark(ERR_STATE *es) es->err_line[i] = thread_es->err_line[j]; es->err_func[i] = thread_es->err_func[j]; - thread_es->err_flags[j] = 0; - thread_es->err_buffer[j] = 0; - thread_es->err_data[j] = NULL; - thread_es->err_data_size[j] = 0; - thread_es->err_file[j] = NULL; - thread_es->err_line[j] = 0; - thread_es->err_func[j] = NULL; + thread_es->err_flags[j] = 0; + thread_es->err_buffer[j] = 0; + thread_es->err_data[j] = NULL; + thread_es->err_data_size[j] = 0; + thread_es->err_data_flags[j] = 0; + thread_es->err_file[j] = NULL; + thread_es->err_line[j] = 0; + thread_es->err_func[j] = NULL; } if (i > 0) { + thread_es->top = top; /* If we moved anything, es's stack always starts at [0]. */ es->top = i - 1; es->bottom = ERR_NUM_ERRORS - 1; -- Gitee From f8bd1269d946576ba0c8d5d1fe48089162a179cf Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Oct 2023 15:42:22 +0100 Subject: [PATCH 44/67] Fix a use-after-free in qrx_proces_pkt When calling qrx_relocate_buffer, both the rxe and the pointer to the token may be changing locations. We have to use a temporary copy of the token pointer to avoid referencing the old location of the rxe. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- ssl/quic/quic_record_rx.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index 6756ddb151..c75b4e93be 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -939,10 +939,19 @@ static int qrx_process_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe, * * Relocate token buffer and fix pointer. */ - if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL - && !qrx_relocate_buffer(qrx, &rxe, &i, &rxe->hdr.token, - rxe->hdr.token_len)) - goto malformed; + if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) { + const unsigned char *token = rxe->hdr.token; + + /* + * This may change the value of rxe and change the value of the token + * pointer as well. So we must make a temporary copy of the pointer to + * the token, and then copy it back into the new location of the rxe + */ + if (!qrx_relocate_buffer(qrx, &rxe, &i, &token, rxe->hdr.token_len)) + goto malformed; + + rxe->hdr.token = token; + } /* Now remove header protection. */ *pkt = orig_pkt; -- Gitee From 484b2cfdd5c10034ef56a73c41416b0f1a24d363 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Oct 2023 15:55:48 +0100 Subject: [PATCH 45/67] Add a HISTORY section in the docs about the new ERR_STATE functions Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- doc/man3/OSSL_ERR_STATE_save.pod | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/man3/OSSL_ERR_STATE_save.pod b/doc/man3/OSSL_ERR_STATE_save.pod index 05c738fc55..93c4b8f473 100644 --- a/doc/man3/OSSL_ERR_STATE_save.pod +++ b/doc/man3/OSSL_ERR_STATE_save.pod @@ -70,6 +70,10 @@ missing the auxiliary error data. L, L, L +=head1 HISTORY + +All of these functions were added in OpenSSL 3.2. + =head1 COPYRIGHT Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. -- Gitee From 30605913ea2aa12cef3876afb63a1e98b4d838db Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Oct 2023 16:10:12 +0100 Subject: [PATCH 46/67] Add a test for OSSL_ERR_STATE_save_to_mark() Add a test for the recently added function OSSL_ERR_STATE_save_to_mark(). We can just modify the existing test_save_restore() to add this in. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- test/errtest.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/test/errtest.c b/test/errtest.c index dbf07f8a72..2a66b483fe 100644 --- a/test/errtest.c +++ b/test/errtest.c @@ -334,7 +334,12 @@ static int test_clear_error(void) return res; } -static int test_save_restore(void) +/* + * Test saving and restoring error state. + * Test 0: Save using OSSL_ERR_STATE_save() + * Test 1: Save using OSSL_ERR_STATE_save_to_mark() + */ +static int test_save_restore(int idx) { ERR_STATE *es; int res = 0, i, flags = -1; @@ -350,15 +355,25 @@ static int test_save_restore(void) if (!TEST_ulong_gt(mallocfail, 0)) goto err; + if (idx == 1 && !TEST_int_eq(ERR_set_mark(), 1)) + goto err; + ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, testdata); interr = ERR_peek_last_error(); if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())) goto err; - OSSL_ERR_STATE_save(es); + if (idx == 0) { + OSSL_ERR_STATE_save(es); - if (!TEST_ulong_eq(ERR_peek_last_error(), 0)) - goto err; + if (!TEST_ulong_eq(ERR_peek_last_error(), 0)) + goto err; + } else { + OSSL_ERR_STATE_save_to_mark(es); + + if (!TEST_ulong_ne(ERR_peek_last_error(), 0)) + goto err; + } for (i = 0; i < 2; i++) { OSSL_ERR_STATE_restore(es); @@ -374,10 +389,12 @@ static int test_save_restore(void) OSSL_ERR_STATE_restore(es); /* verify them all */ - if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, - &data, &flags), mallocfail) - || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) - goto err; + if (idx == 0 || i == 0) { + if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, + &data, &flags), mallocfail) + || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) + goto err; + } if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, &data, &flags), interr) @@ -385,10 +402,12 @@ static int test_save_restore(void) || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) goto err; - if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, - &data, &flags), mallocfail) - || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) - goto err; + if (idx == 0) { + if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, + &data, &flags), mallocfail) + || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) + goto err; + } if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, &data, &flags), interr) @@ -415,7 +434,7 @@ int setup_tests(void) ADD_TEST(test_print_error_format); #endif ADD_TEST(test_marks); - ADD_TEST(test_save_restore); + ADD_ALL_TESTS(test_save_restore, 2); ADD_TEST(test_clear_error); return 1; } -- Gitee From 5acca78f97479bd1904f482c64962efba111d78b Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 12 Oct 2023 16:56:00 +0100 Subject: [PATCH 47/67] Some cleanups in the quic-client fuzzer Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- fuzz/quic-client.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/fuzz/quic-client.c b/fuzz/quic-client.c index 548ed7ec32..0d319d1c34 100644 --- a/fuzz/quic-client.c +++ b/fuzz/quic-client.c @@ -8,13 +8,7 @@ * or in the file LICENSE in the source distribution. */ -#include -#include #include -#include -#include -#include -#include #include #include #include "fuzzer.h" @@ -23,21 +17,6 @@ /* unused, to avoid warning. */ static int idx; -#define FUZZTIME 1485898104 - -#define TIME_IMPL(t) { if (t != NULL) *t = FUZZTIME; return FUZZTIME; } - -/* - * This might not work in all cases (and definitely not on Windows - * because of the way linkers are) and callees can still get the - * current time instead of the fixed time. This will just result - * in things not being fully reproducible and have a slightly - * different coverage. - */ -#if !defined(_WIN32) -time_t time(time_t *t) TIME_IMPL(t) -#endif - int FuzzerInitialize(int *argc, char ***argv) { STACK_OF(SSL_COMP) *comp_methods; @@ -82,14 +61,9 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) ina.s_addr = htonl(0x7f000001UL); - if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), - htons(4433))) + if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433))) goto end; - /* - OPENSSL_assert(SSL_set_min_proto_version(client, 0) == 1); - OPENSSL_assert(SSL_set_cipher_list(client, "ALL:eNULL:@SECLEVEL=0") == 1); - */ SSL_set_tlsext_host_name(client, "localhost"); in = BIO_new(BIO_s_dgram_mem()); if (in == NULL) @@ -118,7 +92,6 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) break; if (size > 0) - /* OPENSSL_assert((size_t)BIO_write(in, buf+2, size) == size); */ BIO_write(in, buf+2, size); len -= size + 2; buf += size + 2; -- Gitee From 06e4d85503ce9ff025b372e2b3ef1372f7e5ca40 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 13 Oct 2023 14:23:40 +0100 Subject: [PATCH 48/67] Drop FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION for some builds Some builds that weren't doing fuzzing were defining this which makes no sense and is not appropriate for non-fuzzing builds. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c994d4f96..eb9765f542 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -183,7 +183,7 @@ jobs: - name: checkout fuzz/corpora submodule run: git submodule update --init --depth 1 fuzz/corpora - name: config - run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION && perl configdata.pm --dump + run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips && perl configdata.pm --dump - name: make run: make -s -j4 - name: get cpu info @@ -345,7 +345,7 @@ jobs: - name: checkout fuzz/corpora submodule run: git submodule update --init --depth 1 fuzz/corpora - name: config - run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-brotli -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DPEDANTIC && perl configdata.pm --dump + run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-brotli -DPEDANTIC && perl configdata.pm --dump - name: make run: make -s -j4 - name: get cpu info @@ -367,7 +367,7 @@ jobs: - name: checkout fuzz/corpora submodule run: git submodule update --init --depth 1 fuzz/corpora - name: config - run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-zstd -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DPEDANTIC && perl configdata.pm --dump + run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-zstd -DPEDANTIC && perl configdata.pm --dump - name: make run: make -s -j4 - name: get cpu info -- Gitee From 64cfc8ede90436ad5b9870d5740b95b90647bbcf Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 13 Oct 2023 16:33:31 +0100 Subject: [PATCH 49/67] If an error occurs constructing the quic record layer, free it properly We need to call quic_free() to free the record layer to ensure than any BIO that was already set is also freed. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- ssl/quic/quic_tls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssl/quic/quic_tls.c b/ssl/quic/quic_tls.c index a1bcedbfb0..af4af56c77 100644 --- a/ssl/quic/quic_tls.c +++ b/ssl/quic/quic_tls.c @@ -85,6 +85,7 @@ struct ossl_record_layer_st { }; static int quic_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio); +static int quic_free(OSSL_RECORD_LAYER *r); static int quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, @@ -189,7 +190,7 @@ quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, return 1; err: *retrl = NULL; - OPENSSL_free(rl); + quic_free(rl); return 0; } -- Gitee From 51905cc37d4a93d9ad58a945378018966fa4b259 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 16 Oct 2023 13:10:33 +0100 Subject: [PATCH 50/67] Teach the quic-client fuzzer about time We allow the fuzzer to influence the time between different packets using the fake time capability. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- fuzz/build.info | 4 +-- fuzz/quic-client.c | 81 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/fuzz/build.info b/fuzz/build.info index a068c2f230..de7cadc79e 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -95,7 +95,7 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] SOURCE[quic-client]=quic-client.c driver.c fuzz_rand.c INCLUDE[quic-client]=../include {- $ex_inc -} - DEPEND[quic-client]=../libcrypto ../libssl {- $ex_lib -} + DEPEND[quic-client]=../libcrypto.a ../libssl.a {- $ex_lib -} SOURCE[server]=server.c driver.c fuzz_rand.c INCLUDE[server]=../include {- $ex_inc -} @@ -194,7 +194,7 @@ IF[{- !$disabled{tests} -}] SOURCE[quic-client-test]=quic-client.c test-corpus.c fuzz_rand.c INCLUDE[quic-client-test]=../include - DEPEND[quic-client-test]=../libcrypto ../libssl + DEPEND[quic-client-test]=../libcrypto.a ../libssl.a SOURCE[server-test]=server.c test-corpus.c fuzz_rand.c INCLUDE[server-test]=../include diff --git a/fuzz/quic-client.c b/fuzz/quic-client.c index 0d319d1c34..2dc2b3c9b2 100644 --- a/fuzz/quic-client.c +++ b/fuzz/quic-client.c @@ -13,10 +13,19 @@ #include #include "fuzzer.h" #include "internal/sockets.h" +#include "internal/time.h" +#include "internal/quic_ssl.h" /* unused, to avoid warning. */ static int idx; +static OSSL_TIME fake_now; + +static OSSL_TIME fake_now_cb(void *arg) +{ + return fake_now; +} + int FuzzerInitialize(int *argc, char ***argv) { STACK_OF(SSL_COMP) *comp_methods; @@ -42,6 +51,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) SSL_CTX *ctx; BIO_ADDR *peer_addr = NULL; struct in_addr ina = {0}; + struct timeval tv; if (len == 0) return 0; @@ -55,6 +65,10 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) if (client == NULL) goto end; + fake_now = ossl_ms2time(1); + if (!ossl_quic_conn_set_override_now_cb(client, fake_now_cb, NULL)) + goto end; + peer_addr = BIO_ADDR_new(); if (peer_addr == NULL) goto end; @@ -84,27 +98,30 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) if (SSL_set1_initial_peer_addr(client, peer_addr) != 1) goto end; SSL_set_connect_state(client); - while (len > 3) - { - size_t size = buf[0] + (buf[1] << 8); - if (size > len - 2) - break; - - if (size > 0) - BIO_write(in, buf+2, size); - len -= size + 2; - buf += size + 2; + for (;;) { + size_t size; + uint64_t nxtpktms = 0; + OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout; + int isinf, ret; + + if (len >= 2) { + nxtpktms = buf[0] + (buf[1] << 8); + nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms)); + len -= 2; + buf += 2; + } - if (SSL_do_handshake(client) == 1) { - /* - * Keep reading application data until there are no more datagrams - * to inject or a fatal error occurs - */ - uint8_t tmp[1024]; - int ret; + for (;;) { + if ((ret = SSL_do_handshake(client)) == 1) { + /* + * Keep reading application data until there are no more + * datagrams to inject or a fatal error occurs + */ + uint8_t tmp[1024]; - ret = SSL_read(client, tmp, sizeof(tmp)); + ret = SSL_read(client, tmp, sizeof(tmp)); + } if (ret <= 0) { switch (SSL_get_error(client, ret)) { case SSL_ERROR_WANT_READ: @@ -114,7 +131,35 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) goto end; } } + + if (!SSL_get_event_timeout(client, &tv, &isinf)) + goto end; + + if (isinf) { + fake_now = nxtpkt; + break; + } else { + nxttimeout = ossl_time_add(fake_now, + ossl_time_from_timeval(tv)); + if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) { + fake_now = nxtpkt; + break; + } + fake_now = nxttimeout; + } } + + if (len <= 3) + break; + + size = buf[0] + (buf[1] << 8); + if (size > len - 2) + break; + + if (size > 0) + BIO_write(in, buf+2, size); + len -= size + 2; + buf += size + 2; } end: SSL_free(client); -- Gitee From 6e2a87d050c4531915d2253a5e1dbf1db98b1e7a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 16 Oct 2023 17:24:56 +0100 Subject: [PATCH 51/67] Further tweaks to the CI runs for fuzzing Have a new job just to run the fuzz tests with fuzzing build mode enabled. Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- .github/workflows/ci.yml | 17 +++++++++++++++++ .github/workflows/static-analysis.yml | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb9765f542..815f7c61b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,6 +193,23 @@ jobs: - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 + fuzz_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: checkout fuzz/corpora submodule + run: git submodule update --init --depth 1 fuzz/corpora + - name: config + run: ./config --banner=Configured --debug -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-weak-ssl-ciphers enable-ssl3 enable-ssl3-method enable-nextprotoneg && perl configdata.pm --dump + - name: make + run: make -s -j4 + - name: get cpu info + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c + - name: make test + run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 TESTS="test_fuzz*" + memory_sanitizer: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 11d1b03abd..05330f02d8 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -26,7 +26,7 @@ jobs: --post-data "token=${{ secrets.COVERITY_TOKEN }}&project=openssl%2Fopenssl" \ --progress=dot:giga -O coverity_tool.tgz - name: config - run: CC=gcc ./config --banner=Configured --debug enable-fips enable-rc5 enable-md2 enable-ssl3 enable-nextprotoneg enable-ssl3-method enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 no-shared enable-buildtest-c++ enable-external-tests -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + run: CC=gcc ./config --banner=Configured --debug enable-fips enable-rc5 enable-md2 enable-ssl3 enable-nextprotoneg enable-ssl3-method enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 no-shared enable-buildtest-c++ enable-external-tests -DPEDANTIC - name: config dump run: ./configdata.pm --dump - name: tool install -- Gitee From 999a15de295814f5e8de973c208d15e25957d555 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 19 Oct 2023 10:07:53 +0100 Subject: [PATCH 52/67] Update the corpora files to include the new quic-client subdir Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- fuzz/corpora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/corpora b/fuzz/corpora index 7bdc71fa62..21c4851c48 160000 --- a/fuzz/corpora +++ b/fuzz/corpora @@ -1 +1 @@ -Subproject commit 7bdc71fa62c88173b8f818dd1646ac59b0eadebe +Subproject commit 21c4851c48af74287cb82e567163c4d0a666ad87 -- Gitee From ed283c9f1822660552c172bfa6704fbf5f361735 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 19 Oct 2023 14:54:58 +0100 Subject: [PATCH 53/67] Don't run the QUIC client fuzzer if QUIC is disabled Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/22368) Signed-off-by: fly2x --- test/recipes/99-test_fuzz_quic_client.t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/recipes/99-test_fuzz_quic_client.t b/test/recipes/99-test_fuzz_quic_client.t index 2a2849035a..a22d0d0c32 100644 --- a/test/recipes/99-test_fuzz_quic_client.t +++ b/test/recipes/99-test_fuzz_quic_client.t @@ -15,6 +15,9 @@ use OpenSSL::Test::Utils; my $fuzzer = "quic-client"; setup("test_fuzz_${fuzzer}"); +plan skip_all => "This test requires quic support" + if disabled("quic"); + plan tests => 2; # one more due to below require_ok(...) require_ok(srctop_file('test','recipes','fuzz.pl')); -- Gitee From 77dbf7dd4df13550c125b89465cab398ad77460f Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 19 Oct 2023 17:19:44 +0200 Subject: [PATCH 54/67] run-checker-daily.yml: If the openssl app is not built do not run it Reviewed-by: Todd Short Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/22443) Signed-off-by: fly2x --- .github/workflows/run-checker-daily.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-checker-daily.yml b/.github/workflows/run-checker-daily.yml index fdd07294a4..0dbbac285f 100644 --- a/.github/workflows/run-checker-daily.yml +++ b/.github/workflows/run-checker-daily.yml @@ -147,6 +147,6 @@ jobs: - name: get cpu info run: | cat /proc/cpuinfo - ./util/opensslwrap.sh version -c + if [ -x apps/openssl ] ; then ./util/opensslwrap.sh version -c ; fi - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} -- Gitee From 29e15e5095db66c4aa65bb28803c2ed27f41abac Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 23 Oct 2023 14:26:32 +0200 Subject: [PATCH 55/67] quic_record, quicapi, and quicfaults tests do not support fuzzing builds Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22472) Signed-off-by: fly2x --- .github/workflows/fuzz-checker.yml | 1 + test/recipes/70-test_quic_record.t | 3 +++ test/recipes/75-test_quicapi.t | 3 +++ test/recipes/90-test_quicfaults.t | 3 +++ 4 files changed, 10 insertions(+) diff --git a/.github/workflows/fuzz-checker.yml b/.github/workflows/fuzz-checker.yml index 766a4a1326..f476b525cf 100644 --- a/.github/workflows/fuzz-checker.yml +++ b/.github/workflows/fuzz-checker.yml @@ -23,6 +23,7 @@ jobs: config: enable-fuzz-afl no-module, install: afl++-clang, cc: afl-clang-fast + tests: - }, { name: libFuzzer, config: enable-fuzz-libfuzzer enable-asan enable-ubsan, diff --git a/test/recipes/70-test_quic_record.t b/test/recipes/70-test_quic_record.t index 3fd782000c..52acaa8aed 100644 --- a/test/recipes/70-test_quic_record.t +++ b/test/recipes/70-test_quic_record.t @@ -14,6 +14,9 @@ setup("test_quic_record"); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; + plan tests => 1; ok(run(test(["quic_record_test"]))); diff --git a/test/recipes/75-test_quicapi.t b/test/recipes/75-test_quicapi.t index bd411f221c..e1ce5eabb2 100644 --- a/test/recipes/75-test_quicapi.t +++ b/test/recipes/75-test_quicapi.t @@ -22,6 +22,9 @@ my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; + plan tests => ($no_fips ? 0 : 1) # quicapitest with fips + 1; # quicapitest with default provider diff --git a/test/recipes/90-test_quicfaults.t b/test/recipes/90-test_quicfaults.t index 7fa039a370..710fdad869 100644 --- a/test/recipes/90-test_quicfaults.t +++ b/test/recipes/90-test_quicfaults.t @@ -20,6 +20,9 @@ use lib bldtop_dir('.'); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; + plan tests => 2; ok(run(test(["quicfaultstest", srctop_dir("test", "certs")])), -- Gitee From 449abf9ba7ca8d896d5ad936da6c0c902b5011c2 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 11 Oct 2023 12:19:23 +1100 Subject: [PATCH 56/67] rand: improve error message for rand pool overflows Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22394) Signed-off-by: fly2x --- crypto/rand/rand_pool.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crypto/rand/rand_pool.c b/crypto/rand/rand_pool.c index 8dc230b540..8d77b77fd2 100644 --- a/crypto/rand/rand_pool.c +++ b/crypto/rand/rand_pool.c @@ -249,7 +249,11 @@ size_t ossl_rand_pool_bytes_needed(RAND_POOL *pool, unsigned int entropy_factor) if (bytes_needed > pool->max_len - pool->len) { /* not enough space left */ - ERR_raise(ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW); + ERR_raise_data(ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW, + "entropy_factor=%u, entropy_needed=%zu, bytes_needed=%zu," + "pool->max_len=%zu, pool->len=%zu", + entropy_factor, entropy_needed, bytes_needed, + pool->max_len, pool->len); return 0; } -- Gitee From b4ec4b194136502a944cda85253d4799d00cedb5 Mon Sep 17 00:00:00 2001 From: "Matthias St. Pierre" Date: Mon, 16 Oct 2023 01:35:48 +0200 Subject: [PATCH 57/67] rand: fix seeding from a weak entropy source The 'rand_generate' method is not well suited for being used with weak entropy sources in the 'get_entropy' callback, because the caller needs to provide a preallocated buffer without knowing how much bytes are actually needed to collect the required entropy. Instead we use the 'rand_get_seed' and 'rand_clear_seed' methods which were exactly designed for this purpose: it's the callee who allocates and fills the buffer, and finally cleans it up again. The 'rand_get_seed' and 'rand_clear_seed' methods are currently optional for a provided random generator. We could fall back to using 'rand_generate' if those methods are not implemented. However, imo it would be better to simply make them an officially documented requirement for seed sources. Fixes #22332 Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale Reviewed-by: Richard Levitte Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22394) Signed-off-by: fly2x --- crypto/evp/evp_rand.c | 68 ++++++++++++++++++++++ crypto/rand/prov_seed.c | 34 ++++------- include/crypto/evp.h | 8 +++ providers/implementations/rands/seed_src.c | 45 +++++++------- 4 files changed, 109 insertions(+), 46 deletions(-) diff --git a/crypto/evp/evp_rand.c b/crypto/evp/evp_rand.c index ecfc876cda..50334042a9 100644 --- a/crypto/evp/evp_rand.c +++ b/crypto/evp/evp_rand.c @@ -46,6 +46,8 @@ struct evp_rand_st { OSSL_FUNC_rand_get_ctx_params_fn *get_ctx_params; OSSL_FUNC_rand_set_ctx_params_fn *set_ctx_params; OSSL_FUNC_rand_verify_zeroization_fn *verify_zeroization; + OSSL_FUNC_rand_get_seed_fn *get_seed; + OSSL_FUNC_rand_clear_seed_fn *clear_seed; } /* EVP_RAND */ ; static int evp_rand_up_ref(void *vrand) @@ -236,6 +238,16 @@ static void *evp_rand_from_algorithm(int name_id, fnzeroizecnt++; #endif break; + case OSSL_FUNC_RAND_GET_SEED: + if (rand->get_seed != NULL) + break; + rand->get_seed = OSSL_FUNC_rand_get_seed(fns); + break; + case OSSL_FUNC_RAND_CLEAR_SEED: + if (rand->clear_seed != NULL) + break; + rand->clear_seed = OSSL_FUNC_rand_clear_seed(fns); + break; } } /* @@ -680,3 +692,59 @@ int EVP_RAND_verify_zeroization(EVP_RAND_CTX *ctx) evp_rand_unlock(ctx); return res; } + +int evp_rand_can_seed(EVP_RAND_CTX *ctx) +{ + return ctx->meth->get_seed != NULL; +} + +static size_t evp_rand_get_seed_locked(EVP_RAND_CTX *ctx, + unsigned char **buffer, + int entropy, + size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, + size_t adin_len) +{ + if (ctx->meth->get_seed != NULL) + return ctx->meth->get_seed(ctx->algctx, buffer, + entropy, min_len, max_len, + prediction_resistance, + adin, adin_len); + return 0; +} + +size_t evp_rand_get_seed(EVP_RAND_CTX *ctx, + unsigned char **buffer, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, size_t adin_len) +{ + int res; + + if (!evp_rand_lock(ctx)) + return 0; + res = evp_rand_get_seed_locked(ctx, + buffer, + entropy, min_len, max_len, + prediction_resistance, + adin, adin_len); + evp_rand_unlock(ctx); + return res; +} + +static void evp_rand_clear_seed_locked(EVP_RAND_CTX *ctx, + unsigned char *buffer, size_t b_len) +{ + if (ctx->meth->clear_seed != NULL) + ctx->meth->clear_seed(ctx->algctx, buffer, b_len); +} + +void evp_rand_clear_seed(EVP_RAND_CTX *ctx, + unsigned char *buffer, size_t b_len) +{ + if (!evp_rand_lock(ctx)) + return; + evp_rand_clear_seed_locked(ctx, buffer, b_len); + evp_rand_unlock(ctx); +} diff --git a/crypto/rand/prov_seed.c b/crypto/rand/prov_seed.c index a8128119b5..2985c7f2d8 100644 --- a/crypto/rand/prov_seed.c +++ b/crypto/rand/prov_seed.c @@ -8,6 +8,7 @@ */ #include "rand_local.h" +#include "crypto/evp.h" #include "crypto/rand.h" #include "crypto/rand_pool.h" #include "internal/core.h" @@ -44,31 +45,13 @@ size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { - unsigned char *buf; EVP_RAND_CTX *rng = ossl_rand_get0_seed_noncreating(ctx); - size_t ret; - if (rng == NULL) + if (rng != NULL && evp_rand_can_seed(rng)) + return evp_rand_get_seed(rng, pout, entropy, min_len, max_len, + 0, NULL, 0); + else return ossl_rand_get_entropy(ctx, pout, entropy, min_len, max_len); - - /* Determine how many bytes to generate */ - ret = entropy > 0 ? (size_t)(7 + entropy) / 8 : min_len; - if (ret < min_len) - ret = min_len; - else if (ret > max_len) - ret = max_len; - - /* Allocate the return buffer */ - if ((buf = OPENSSL_secure_malloc(ret)) == NULL) - return 0; - - /* Fill the buffer */ - if (!EVP_RAND_generate(rng, buf, ret, entropy, 0, NULL, 0)) { - OPENSSL_free(buf); - return 0; - } - *pout = buf; - return ret; } void ossl_rand_cleanup_entropy(ossl_unused OSSL_LIB_CTX *ctx, @@ -80,7 +63,12 @@ void ossl_rand_cleanup_entropy(ossl_unused OSSL_LIB_CTX *ctx, void ossl_rand_cleanup_user_entropy(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t len) { - OPENSSL_secure_clear_free(buf, len); + EVP_RAND_CTX *rng = ossl_rand_get0_seed_noncreating(ctx); + + if (rng != NULL && evp_rand_can_seed(rng)) + evp_rand_clear_seed(rng, buf, len); + else + OPENSSL_secure_clear_free(buf, len); } size_t ossl_rand_get_nonce(ossl_unused OSSL_LIB_CTX *ctx, diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 473b95514a..34cea2f9f4 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -953,6 +953,14 @@ int evp_keymgmt_get_number(const EVP_KEYMGMT *keymgmt); int evp_mac_get_number(const EVP_MAC *mac); int evp_md_get_number(const EVP_MD *md); int evp_rand_get_number(const EVP_RAND *rand); +int evp_rand_can_seed(EVP_RAND_CTX *ctx); +size_t evp_rand_get_seed(EVP_RAND_CTX *ctx, + unsigned char **buffer, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, size_t adin_len); +void evp_rand_clear_seed(EVP_RAND_CTX *ctx, + unsigned char *buffer, size_t b_len); int evp_signature_get_number(const EVP_SIGNATURE *signature); int evp_pkey_decrypt_alloc(EVP_PKEY_CTX *ctx, unsigned char **outp, diff --git a/providers/implementations/rands/seed_src.c b/providers/implementations/rands/seed_src.c index e57c9c4d41..e8f7ec9efc 100644 --- a/providers/implementations/rands/seed_src.c +++ b/providers/implementations/rands/seed_src.c @@ -177,33 +177,32 @@ static size_t seed_get_seed(void *vseed, unsigned char **pout, int prediction_resistance, const unsigned char *adin, size_t adin_len) { - size_t bytes_needed; - unsigned char *p; - - /* - * Figure out how many bytes we need. - * This assumes that the seed sources provide eight bits of entropy - * per byte. For lower quality sources, the formula will need to be - * different. - */ - bytes_needed = entropy >= 0 ? (entropy + 7) / 8 : 0; - if (bytes_needed < min_len) - bytes_needed = min_len; - if (bytes_needed > max_len) { - ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK); + size_t ret = 0; + size_t entropy_available = 0; + size_t i; + RAND_POOL *pool; + + pool = ossl_rand_pool_new(entropy, 1, min_len, max_len); + if (pool == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_RAND_LIB); return 0; } - p = OPENSSL_secure_malloc(bytes_needed); - if (p == NULL) - return 0; - if (seed_src_generate(vseed, p, bytes_needed, 0, prediction_resistance, - adin, adin_len) != 0) { - *pout = p; - return bytes_needed; + /* Get entropy by polling system entropy sources. */ + entropy_available = ossl_pool_acquire_entropy(pool); + + if (entropy_available > 0) { + ret = ossl_rand_pool_length(pool); + *pout = ossl_rand_pool_detach(pool); + + /* xor the additional data into the output */ + for (i = 0 ; i < adin_len ; ++i) + (*pout)[i % ret] ^= adin[i]; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK); } - OPENSSL_secure_clear_free(p, bytes_needed); - return 0; + ossl_rand_pool_free(pool); + return ret; } static void seed_clear_seed(ossl_unused void *vdrbg, -- Gitee From 38ddcdbfd819379c5c08fa58af3e3b4fed456985 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 19 Oct 2023 08:37:47 +0200 Subject: [PATCH 58/67] Fix Coverity 1547856: memset() uses only the lowest byte of c Reviewed-by: Hugo Landau Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/22430) Signed-off-by: fly2x --- test/rsa_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rsa_test.c b/test/rsa_test.c index 88c2f6d25d..2d9f6aa3a3 100644 --- a/test/rsa_test.c +++ b/test/rsa_test.c @@ -484,7 +484,7 @@ static int test_EVP_rsa_legacy_key(void) 0x85, 0x20, 0x4f, 0x35, 0x02, 0xfa, 0xda, 0x14, 0x77, 0xfa, 0x08, 0x34, 0x60, 0xc7, 0x93, 0x72, 0xdc, 0xc4, 0x18, 0x70, 0xc1 }; - memset(msgbuf, 0xdeadbeef, 64); + memset(msgbuf, 0xef, 64); ret = (TEST_ptr((p = BN_bin2bn(p_data, sizeof(p_data), NULL))) && TEST_ptr((q = BN_bin2bn(q_data, sizeof(q_data), NULL))) -- Gitee From 0c1ebf2f559bf28c6193a343ec934f890230ef68 Mon Sep 17 00:00:00 2001 From: Pauli Date: Fri, 6 Oct 2023 10:26:23 +1100 Subject: [PATCH 59/67] evp: process key length and iv length early if present evp_cipher_init_internal() takes a params array argument and this is processed late in the initialisation process for some ciphers (AEAD ones). This means that changing the IV length as a parameter will either truncate the IV (very bad if SP 800-38d section 8.2.1 is used) or grab extra uninitialised bytes. Truncation is very bad if SP 800-38d section 8.2.1 is being used to contruct a deterministic IV. This leads to an instant loss of confidentiality. Grabbing extra bytes isn't so serious, it will most likely result in a bad decryption. Problem reported by Tony Battersby of Cybernetics.com but earlier discovered and raised as issue #19822. Fixes CVE-2023-5363 Fixes #19822 Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell Signed-off-by: fly2x --- crypto/evp/evp_enc.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index e1d3eeef64..e9faf31057 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -233,6 +233,42 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, return 0; } +#ifndef FIPS_MODULE + /* + * Fix for CVE-2023-5363 + * Passing in a size as part of the init call takes effect late + * so, force such to occur before the initialisation. + * + * The FIPS provider's internal library context is used in a manner + * such that this is not an issue. + */ + if (params != NULL) { + OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, + OSSL_PARAM_END }; + OSSL_PARAM *q = param_lens; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) + memcpy(q++, p, sizeof(*q)); + + /* + * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synomym for + * OSSL_CIPHER_PARAM_IVLEN so both are covered here. + */ + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) + memcpy(q++, p, sizeof(*q)); + + if (q != param_lens) { + if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); + return 0; + } + } + } +#endif + if (enc) { if (ctx->cipher->einit == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); -- Gitee From bcc80cff48a4e7e006911f3758e0204541ffeb79 Mon Sep 17 00:00:00 2001 From: Pauli Date: Fri, 6 Oct 2023 10:43:46 +1100 Subject: [PATCH 60/67] changes and news entries for CVE-2023-5363 Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell Signed-off-by: fly2x --- CHANGES.md | 11 ++++++++++- NEWS.md | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ef801c2f73..15b5aa0542 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -470,7 +470,15 @@ OpenSSL 3.2 OpenSSL 3.1 ----------- -### Changes between 3.1.2 and 3.1.3 [xx XXX xxxx] +### Changes between 3.1.3 and 3.1.4 [xx XXX xxxx] + +* Fix incorrect key and IV resizing issues when calling EVP_EncryptInit_ex2(), + EVP_DecryptInit_ex2() or EVP_CipherInit_ex2() with OSSL_PARAM parameters + that alter the key or IV length ([CVE-2023-5363]). + + *Paul Dale* + +### Changes between 3.1.2 and 3.1.3 [19 Sep 2023] * Fix POLY1305 MAC implementation corrupting XMM registers on Windows. @@ -20288,6 +20296,7 @@ ndif +[CVE-2023-5363]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5363 [CVE-2023-4807]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-4807 [CVE-2023-3817]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3817 [CVE-2023-3446]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3446 diff --git a/NEWS.md b/NEWS.md index d0312961df..141f9dcc66 100644 --- a/NEWS.md +++ b/NEWS.md @@ -52,7 +52,12 @@ OpenSSL 3.2 OpenSSL 3.1 ----------- -### Major changes between OpenSSL 3.1.2 and OpenSSL 3.1.3 [under development] +### Major changes between OpenSSL 3.1.3 and OpenSSL 3.1.4 [under development] + + * Mitigate incorrect resize handling for symmetric cipher keys and IVs. + ([CVE-2023-5363]) + +### Major changes between OpenSSL 3.1.2 and OpenSSL 3.1.3 [19 Sep 2023] * Fix POLY1305 MAC implementation corrupting XMM registers on Windows ([CVE-2023-4807]) @@ -1502,6 +1507,7 @@ OpenSSL 0.9.x +[CVE-2023-5363]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5363 [CVE-2023-4807]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-4807 [CVE-2023-3817]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3817 [CVE-2023-3446]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3446 -- Gitee From 3e9e3b643465420baffff916d9736a051deb3699 Mon Sep 17 00:00:00 2001 From: Pauli Date: Fri, 6 Oct 2023 10:32:20 +1100 Subject: [PATCH 61/67] test: add unit test for CVE-2023-5363 Reviewed-by: Tomas Mraz Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell Signed-off-by: fly2x --- test/evp_extra_test.c | 253 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 6e61b8e925..0ece891159 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -5051,6 +5051,253 @@ end: return testresult; } +static int aes_gcm_encrypt(const unsigned char *gcm_key, size_t gcm_key_s, + const unsigned char *gcm_iv, size_t gcm_ivlen, + const unsigned char *gcm_pt, size_t gcm_pt_s, + const unsigned char *gcm_aad, size_t gcm_aad_s, + const unsigned char *gcm_ct, size_t gcm_ct_s, + const unsigned char *gcm_tag, size_t gcm_tag_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen, tmplen; + unsigned char outbuf[1024]; + unsigned char outtag[16]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, "AES-256-GCM", ""))) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, + &gcm_ivlen); + + if (!TEST_true(EVP_EncryptInit_ex2(ctx, cipher, gcm_key, gcm_iv, params)) + || (gcm_aad != NULL + && !TEST_true(EVP_EncryptUpdate(ctx, NULL, &outlen, + gcm_aad, gcm_aad_s))) + || !TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, + gcm_pt, gcm_pt_s)) + || !TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))) + goto err; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, + outtag, sizeof(outtag)); + + if (!TEST_true(EVP_CIPHER_CTX_get_params(ctx, params)) + || !TEST_mem_eq(outbuf, outlen, gcm_ct, gcm_ct_s) + || !TEST_mem_eq(outtag, gcm_tag_s, gcm_tag, gcm_tag_s)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int aes_gcm_decrypt(const unsigned char *gcm_key, size_t gcm_key_s, + const unsigned char *gcm_iv, size_t gcm_ivlen, + const unsigned char *gcm_pt, size_t gcm_pt_s, + const unsigned char *gcm_aad, size_t gcm_aad_s, + const unsigned char *gcm_ct, size_t gcm_ct_s, + const unsigned char *gcm_tag, size_t gcm_tag_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen; + unsigned char outbuf[1024]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if ((cipher = EVP_CIPHER_fetch(testctx, "AES-256-GCM", "")) == NULL) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, + &gcm_ivlen); + + if (!TEST_true(EVP_DecryptInit_ex2(ctx, cipher, gcm_key, gcm_iv, params)) + || (gcm_aad != NULL + && !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outlen, + gcm_aad, gcm_aad_s))) + || !TEST_true(EVP_DecryptUpdate(ctx, outbuf, &outlen, + gcm_ct, gcm_ct_s)) + || !TEST_mem_eq(outbuf, outlen, gcm_pt, gcm_pt_s)) + goto err; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, + (void*)gcm_tag, gcm_tag_s); + + if (!TEST_true(EVP_CIPHER_CTX_set_params(ctx, params)) + ||!TEST_true(EVP_DecryptFinal_ex(ctx, outbuf, &outlen))) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int test_aes_gcm_ivlen_change_cve_2023_5363(void) +{ + /* AES-GCM test data obtained from NIST public test vectors */ + static const unsigned char gcm_key[] = { + 0xd0, 0xc2, 0x67, 0xc1, 0x9f, 0x30, 0xd8, 0x0b, 0x89, 0x14, 0xbb, 0xbf, + 0xb7, 0x2f, 0x73, 0xb8, 0xd3, 0xcd, 0x5f, 0x6a, 0x78, 0x70, 0x15, 0x84, + 0x8a, 0x7b, 0x30, 0xe3, 0x8f, 0x16, 0xf1, 0x8b, + }; + static const unsigned char gcm_iv[] = { + 0xb6, 0xdc, 0xda, 0x95, 0xac, 0x99, 0x77, 0x76, 0x25, 0xae, 0x87, 0xf8, + 0xa3, 0xa9, 0xdd, 0x64, 0xd7, 0x9b, 0xbd, 0x5f, 0x4a, 0x0e, 0x54, 0xca, + 0x1a, 0x9f, 0xa2, 0xe3, 0xf4, 0x5f, 0x5f, 0xc2, 0xce, 0xa7, 0xb6, 0x14, + 0x12, 0x6f, 0xf0, 0xaf, 0xfd, 0x3e, 0x17, 0x35, 0x6e, 0xa0, 0x16, 0x09, + 0xdd, 0xa1, 0x3f, 0xd8, 0xdd, 0xf3, 0xdf, 0x4f, 0xcb, 0x18, 0x49, 0xb8, + 0xb3, 0x69, 0x2c, 0x5d, 0x4f, 0xad, 0x30, 0x91, 0x08, 0xbc, 0xbe, 0x24, + 0x01, 0x0f, 0xbe, 0x9c, 0xfb, 0x4f, 0x5d, 0x19, 0x7f, 0x4c, 0x53, 0xb0, + 0x95, 0x90, 0xac, 0x7b, 0x1f, 0x7b, 0xa0, 0x99, 0xe1, 0xf3, 0x48, 0x54, + 0xd0, 0xfc, 0xa9, 0xcc, 0x91, 0xf8, 0x1f, 0x9b, 0x6c, 0x9a, 0xe0, 0xdc, + 0x63, 0xea, 0x7d, 0x2a, 0x4a, 0x7d, 0xa5, 0xed, 0x68, 0x57, 0x27, 0x6b, + 0x68, 0xe0, 0xf2, 0xb8, 0x51, 0x50, 0x8d, 0x3d, + }; + static const unsigned char gcm_pt[] = { + 0xb8, 0xb6, 0x88, 0x36, 0x44, 0xe2, 0x34, 0xdf, 0x24, 0x32, 0x91, 0x07, + 0x4f, 0xe3, 0x6f, 0x81, + }; + static const unsigned char gcm_ct[] = { + 0xff, 0x4f, 0xb3, 0xf3, 0xf9, 0xa2, 0x51, 0xd4, 0x82, 0xc2, 0xbe, 0xf3, + 0xe2, 0xd0, 0xec, 0xed, + }; + static const unsigned char gcm_tag[] = { + 0xbd, 0x06, 0x38, 0x09, 0xf7, 0xe1, 0xc4, 0x72, 0x0e, 0xf2, 0xea, 0x63, + 0xdb, 0x99, 0x6c, 0x21, + }; + + return aes_gcm_encrypt(gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), + gcm_pt, sizeof(gcm_pt), NULL, 0, + gcm_ct, sizeof(gcm_ct), gcm_tag, sizeof(gcm_tag)) + && aes_gcm_decrypt(gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), + gcm_pt, sizeof(gcm_pt), NULL, 0, + gcm_ct, sizeof(gcm_ct), gcm_tag, sizeof(gcm_tag)); +} + +#ifndef OPENSSL_NO_RC4 +static int rc4_encrypt(const unsigned char *rc4_key, size_t rc4_key_s, + const unsigned char *rc4_pt, size_t rc4_pt_s, + const unsigned char *rc4_ct, size_t rc4_ct_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen, tmplen; + unsigned char outbuf[1024]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, "RC4", ""))) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, + &rc4_key_s); + + if (!TEST_true(EVP_EncryptInit_ex2(ctx, cipher, rc4_key, NULL, params)) + || !TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, + rc4_pt, rc4_pt_s)) + || !TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))) + goto err; + + if (!TEST_mem_eq(outbuf, outlen, rc4_ct, rc4_ct_s)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int rc4_decrypt(const unsigned char *rc4_key, size_t rc4_key_s, + const unsigned char *rc4_pt, size_t rc4_pt_s, + const unsigned char *rc4_ct, size_t rc4_ct_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen; + unsigned char outbuf[1024]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if ((cipher = EVP_CIPHER_fetch(testctx, "RC4", "")) == NULL) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, + &rc4_key_s); + + if (!TEST_true(EVP_DecryptInit_ex2(ctx, cipher, rc4_key, NULL, params)) + || !TEST_true(EVP_DecryptUpdate(ctx, outbuf, &outlen, + rc4_ct, rc4_ct_s)) + || !TEST_mem_eq(outbuf, outlen, rc4_pt, rc4_pt_s)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int test_aes_rc4_keylen_change_cve_2023_5363(void) +{ + /* RC4 test data obtained from RFC 6229 */ + static const struct { + unsigned char key[5]; + unsigned char padding[11]; + } rc4_key = { + { /* Five bytes of key material */ + 0x83, 0x32, 0x22, 0x77, 0x2a, + }, + { /* Random padding to 16 bytes */ + 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, 0xaa, 0x32, 0x91 + } + }; + static const unsigned char rc4_pt[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char rc4_ct[] = { + 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, + 0x2e, 0x87, 0x9e, 0x92, 0xa4, 0x97, 0xef, 0xda + }; + + if (lgcyprov == NULL) + return TEST_skip("Test requires legacy provider to be loaded"); + + return rc4_encrypt(rc4_key.key, sizeof(rc4_key.key), + rc4_pt, sizeof(rc4_pt), rc4_ct, sizeof(rc4_ct)) + && rc4_decrypt(rc4_key.key, sizeof(rc4_key.key), + rc4_pt, sizeof(rc4_pt), rc4_ct, sizeof(rc4_ct)); +} +#endif + int setup_tests(void) { OPTION_CHOICE o; @@ -5199,6 +5446,12 @@ int setup_tests(void) ADD_TEST(test_sign_continuation); + /* Test cases for CVE-2023-5363 */ + ADD_TEST(test_aes_gcm_ivlen_change_cve_2023_5363); +#ifndef OPENSSL_NO_RC4 + ADD_TEST(test_aes_rc4_keylen_change_cve_2023_5363); +#endif + return 1; } -- Gitee From ed79dd01d5ab9436731a2ad2d2bd6f3e1da9a3dc Mon Sep 17 00:00:00 2001 From: Nate Karstens Date: Fri, 20 Oct 2023 11:24:33 -0500 Subject: [PATCH 62/67] Add notes on use of strdup Added notes to OPENSSL_INIT_set_config_filename and OPENSSL_INIT_set_config_appname explaining why strdup is used instead of OPENSSL_strdup. CLA: trivial Co-authored-by: Jean Apolo Signed-off-by: Jean Apolo Signed-off-by: Nate Karstens Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/21742) Signed-off-by: fly2x --- crypto/conf/conf_lib.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crypto/conf/conf_lib.c b/crypto/conf/conf_lib.c index 05e7bf19cc..99e9f8c987 100644 --- a/crypto/conf/conf_lib.c +++ b/crypto/conf/conf_lib.c @@ -421,6 +421,12 @@ OPENSSL_INIT_SETTINGS *OPENSSL_INIT_new(void) #ifndef OPENSSL_NO_STDIO +/* + * If CRYPTO_set_mem_functions is called after this, then + * memory allocation and deallocation in this function can + * become disjointed. Avoid this by always using standard + * strdup & free instead of OPENSSL_strdup & OPENSSL_free. + */ int OPENSSL_INIT_set_config_filename(OPENSSL_INIT_SETTINGS *settings, const char *filename) { @@ -444,6 +450,12 @@ void OPENSSL_INIT_set_config_file_flags(OPENSSL_INIT_SETTINGS *settings, settings->flags = flags; } +/* + * If CRYPTO_set_mem_functions is called after this, then + * memory allocation and deallocation in this function can + * become disjointed. Avoid this by always using standard + * strdup & free instead of OPENSSL_strdup & OPENSSL_free. + */ int OPENSSL_INIT_set_config_appname(OPENSSL_INIT_SETTINGS *settings, const char *appname) { -- Gitee From 7038eba99f05de7812e19333e262e40de2d0f789 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 15:50:25 +0100 Subject: [PATCH 63/67] Add QUIC README file Signed-off-by: fly2x --- README-QUIC.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 README-QUIC.md diff --git a/README-QUIC.md b/README-QUIC.md new file mode 100644 index 0000000000..02708eda2c --- /dev/null +++ b/README-QUIC.md @@ -0,0 +1,98 @@ +Using OpenSSL with QUIC +======================= + +From OpenSSL 3.2, OpenSSL features support for making QUIC connections as a +client. + +Users interested in using the new QUIC functionality are encouraged to look at +some of the following resources: + +- The [openssl-quic(7) manual page], which provides a basic reference overview + of QUIC functionality and how use of QUIC differs from use of TLS with regard + to our API; +- The new [OpenSSL Guide], which provides introductory guides + on the use of TLS, QUIC, and other OpenSSL functionality. See the + [ossl-guide-introduction(7) manual page][OpenSSL Guide] for the index. +- The [Demo-Driven Design (DDD)][DDD] demos, which demonstrate the use of QUIC + using simple examples. These can be [found in the source tree under + `doc/designs/ddd`]. +- The [demo found in `demos/http3`], which provides an HTTP/3 client example + using the nghttp3 HTTP/3 library. + +FAQ +--- + +### Why would I want to use QUIC, and what functionality does QUIC offer relative to TLS or DTLS? + +QUIC is a state-of-the-art secure transport protocol carried over UDP. It can +serve many of the use cases of TLS as well as those of DTLS. QUIC delivers +a number of advantages: + +- It supports multiple streams of communication, allowing application protocols + built on QUIC to create arbitrarily many bytestreams for communication between + a client and server. This allows an application protocol to avoid head-of-line + blocking and allows an application to open additional logical streams without + any round trip penalty, unlike opening an additional TCP connection. + +- Since QUIC is the basis of HTTP/3, support for QUIC also enables applications + to use HTTP/3 using a suitable third-party library. + +- Future versions of OpenSSL will offer support for 0-RTT connection + initiation, allowing a connection to be initiated to a server and application + data to be transmitted without any waiting time. This is similar to TLS 1.3's + 0-RTT functionality but also avoids the round trip needed to open a TCP + socket; thus, it is similar to a combination of TLS 1.3 0-RTT and TCP Fast + Open. + +- Future versions of OpenSSL will offer support for connection + migration, allowing connections to seamlessly survive IP address changes. + +- Future versions of OpenSSL will offer support for the QUIC + datagram extension, allowing support for both TLS and DTLS-style use cases on + a single connection. + +- Because most QUIC implementations, including OpenSSL's implementation, are + implemented as an application library rather than by an operating system, an + application can gain the benefit of QUIC without needing to wait for an OS + update to be deployed. Future evolutions and enhancements to the QUIC protocol + can be delivered as quickly as an application can be updated without + dependency on an OS update cadence. + +- Because QUIC is UDP-based, it is possible to multiplex a QUIC connection + on the same UDP socket as some other UDP-based protocols, such as RTP. + +For more background information on OpenSSL's QUIC implementation, see the +[openssl-quic(7) manual page]. + +### How can I use HTTP/3 with OpenSSL? + +There are many HTTP/3 implementations in C available. The use of one such HTTP/3 +library with OpenSSL QUIC is demonstrated via the [demo found in `demos/http3`]. + +### How can I use OpenSSL QUIC in my own application for a different protocol? + +The [OpenSSL Guide] provides introductory examples for how to make use of +OpenSSL QUIC. + +The [openssl-quic(7) manual page] and the [Demo-Driven Design (DDD)][DDD] demos +may also be helpful to illustrate the changes needed if you are trying to adapt +an existing application. + +### How can I test QUIC using `openssl s_client`? + +There is basic support for single-stream QUIC using `openssl s_client`: + +```shell +$ openssl s_client -quic -alpn ossltest -connect www.example.com:12345 +``` + +This connects to a QUIC server using the specified ALPN protocol name and opens +a single bidirectional stream. Data can be passed via stdin/stdout as usual. +This allows test usage of QUIC using simple TCP/TLS-like usage. + +[openssl-quic(7) manual page]: https://www.openssl.org/docs/manmaster/man7/openssl-quic.html +[OpenSSL guide]: https://www.openssl.org/docs/manmaster/man7/ossl-guide-introduction.html +[DDD]: https://github.com/openssl/openssl/tree/master/doc/designs/ddd +[found in the source tree under `doc/designs/ddd`]: ./doc/designs/ddd/ +[demo found in `demos/http3`]: ./demos/http3/ +[openssl-quic-background(7) manual page]: https://www.openssl.org/docs/manmaster/man7/openssl-quic-background.html -- Gitee From 386b2b6d049a13d76973231eb4896615160d646c Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 16 Oct 2023 15:50:30 +0100 Subject: [PATCH 64/67] Adjust mdl configuration Reviewed-by: Matthias St. Pierre Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22405) Signed-off-by: fly2x --- util/markdownlint.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/markdownlint.rb b/util/markdownlint.rb index 3833a252ef..2179f15999 100644 --- a/util/markdownlint.rb +++ b/util/markdownlint.rb @@ -8,12 +8,14 @@ rule 'MD003', :style => :setext_with_atx # Code blocks may be fenced or indented, both are OK... # but they must be consistent throughout each file. rule 'MD046', :style => :consistent -# Not possible to line-break tables. -rule 'MD013', :tables => false # Bug in mdl, https://github.com/markdownlint/markdownlint/issues/313 exclude_rule 'MD007' +# Not possible to line-break tables (:tables => false) +# Not possible to line-break headers (currently cannot be selectively exempted) +exclude_rule 'MD013' + exclude_rule 'MD004' # Unordered list style TODO(fix?) exclude_rule 'MD005' # Inconsistent indentation for list items at the same level exclude_rule 'MD006' # Consider starting bulleted lists at the beginning of the line -- Gitee From da6b886c5912bfeeb6ab8caa72c26e3d7f57797f Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 20 Oct 2023 12:33:25 +0100 Subject: [PATCH 65/67] When requeueing deferred URXEs retain the order If a URXE cannot be processed yet then we add it to the urx_deferred list. Later, when they can be processed, we requeue them in the urx_pending list. We must not reverse the order when doing so. We want to process the URXEs in the order that they were received. Reviewed-by: Hugo Landau Reviewed-by: Paul Dale Reviewed-by: Todd Short Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22452) Signed-off-by: fly2x --- ssl/quic/quic_record_rx.c | 2 +- .../75-test_quicapi_data/ssltraceref-zlib.txt | 14 +++++++------- test/recipes/75-test_quicapi_data/ssltraceref.txt | 14 +++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index c75b4e93be..4d0493baff 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -280,7 +280,7 @@ static void qrx_requeue_deferred(OSSL_QRX *qrx) while ((e = ossl_list_urxe_head(&qrx->urx_deferred)) != NULL) { ossl_list_urxe_remove(&qrx->urx_deferred, e); - ossl_list_urxe_insert_head(&qrx->urx_pending, e); + ossl_list_urxe_insert_tail(&qrx->urx_pending, e); } } diff --git a/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt b/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt index e8bdee624f..68d3fd86ec 100644 --- a/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt +++ b/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt @@ -127,21 +127,21 @@ Received Packet Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 213 - Packet Number: 0x00000001 + Payload length: 1042 + Packet Number: 0x00000000 Received Packet Packet Type: Handshake Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 1042 - Packet Number: 0x00000000 -Received Frame: Crypto - Offset: 1022 - Len: 192 + Payload length: 213 + Packet Number: 0x00000001 Received Frame: Crypto Offset: 0 Len: 1022 +Received Frame: Crypto + Offset: 1022 + Len: 192 Received TLS Record Header: Version = TLS 1.2 (0x303) diff --git a/test/recipes/75-test_quicapi_data/ssltraceref.txt b/test/recipes/75-test_quicapi_data/ssltraceref.txt index 6b64d0652e..6a6828ec01 100644 --- a/test/recipes/75-test_quicapi_data/ssltraceref.txt +++ b/test/recipes/75-test_quicapi_data/ssltraceref.txt @@ -125,21 +125,21 @@ Received Packet Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 213 - Packet Number: 0x00000001 + Payload length: 1042 + Packet Number: 0x00000000 Received Packet Packet Type: Handshake Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 1042 - Packet Number: 0x00000000 -Received Frame: Crypto - Offset: 1022 - Len: 192 + Payload length: 213 + Packet Number: 0x00000001 Received Frame: Crypto Offset: 0 Len: 1022 +Received Frame: Crypto + Offset: 1022 + Len: 192 Received TLS Record Header: Version = TLS 1.2 (0x303) -- Gitee From fc987e5823f427a0116fee160aa72b194f8831a2 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 23 Oct 2023 09:54:16 +0100 Subject: [PATCH 66/67] Make sure we remember how much data we sent in the event of a retry If a retry occurs we need to reset s->rlayer.wnum so that next time around we remember how much data we already sent. Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22473) Signed-off-by: fly2x --- ssl/record/rec_layer_s3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 260d163a50..845eff9848 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -294,8 +294,10 @@ int ssl3_write_bytes(SSL *ssl, uint8_t type, const void *buf_, size_t len, /* Retry needed */ i = HANDLE_RLAYER_WRITE_RETURN(s, s->rlayer.wrlmethod->retry_write_records(s->rlayer.wrl)); - if (i <= 0) + if (i <= 0) { + s->rlayer.wnum = tot; return i; + } tot += s->rlayer.wpend_tot; s->rlayer.wpend_tot = 0; } /* else no retry required */ @@ -321,6 +323,7 @@ int ssl3_write_bytes(SSL *ssl, uint8_t type, const void *buf_, size_t len, i = ssl->method->ssl_dispatch_alert(ssl); if (i <= 0) { /* SSLfatal() already called if appropriate */ + s->rlayer.wnum = tot; return i; } /* if it went, fall through and send more stuff */ -- Gitee From d409d4edc63827c1b4fe1c244193d36f473c4cbd Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 23 Oct 2023 12:16:44 +0100 Subject: [PATCH 67/67] Add a test for retries when sending app data Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22473) Signed-off-by: fly2x --- test/helpers/ssltestlib.c | 98 ++++++++++++++++++++++++++++++++++++++- test/helpers/ssltestlib.h | 9 ++++ test/sslapitest.c | 98 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 1 deletion(-) diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c index 3ae3e7d4ea..ddc6bb7b64 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -29,13 +29,15 @@ static int tls_dump_gets(BIO *bp, char *buf, int size); static int tls_dump_puts(BIO *bp, const char *str); /* Choose a sufficiently large type likely to be unused for this custom BIO */ -#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER) +#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER) #define BIO_TYPE_MEMPACKET_TEST 0x81 #define BIO_TYPE_ALWAYS_RETRY 0x82 +#define BIO_TYPE_MAYBE_RETRY (0x83 | BIO_TYPE_FILTER) static BIO_METHOD *method_tls_dump = NULL; static BIO_METHOD *meth_mem = NULL; static BIO_METHOD *meth_always_retry = NULL; +static BIO_METHOD *meth_maybe_retry = NULL; static int retry_err = -1; /* Note: Not thread safe! */ @@ -804,6 +806,100 @@ static int always_retry_puts(BIO *bio, const char *str) return retry_err; } +struct maybe_retry_data_st { + unsigned int retrycnt; +}; + +static int maybe_retry_new(BIO *bi); +static int maybe_retry_free(BIO *a); +static int maybe_retry_write(BIO *b, const char *in, int inl); +static long maybe_retry_ctrl(BIO *b, int cmd, long num, void *ptr); + +const BIO_METHOD *bio_s_maybe_retry(void) +{ + if (meth_maybe_retry == NULL) { + if (!TEST_ptr(meth_maybe_retry = BIO_meth_new(BIO_TYPE_MAYBE_RETRY, + "Maybe Retry")) + || !TEST_true(BIO_meth_set_write(meth_maybe_retry, + maybe_retry_write)) + || !TEST_true(BIO_meth_set_ctrl(meth_maybe_retry, + maybe_retry_ctrl)) + || !TEST_true(BIO_meth_set_create(meth_maybe_retry, + maybe_retry_new)) + || !TEST_true(BIO_meth_set_destroy(meth_maybe_retry, + maybe_retry_free))) + return NULL; + } + return meth_maybe_retry; +} + +void bio_s_maybe_retry_free(void) +{ + BIO_meth_free(meth_maybe_retry); +} + +static int maybe_retry_new(BIO *bio) +{ + struct maybe_retry_data_st *data = OPENSSL_zalloc(sizeof(*data)); + + if (data == NULL) + return 0; + + BIO_set_data(bio, data); + BIO_set_init(bio, 1); + return 1; +} + +static int maybe_retry_free(BIO *bio) +{ + struct maybe_retry_data_st *data = BIO_get_data(bio); + + OPENSSL_free(data); + BIO_set_data(bio, NULL); + BIO_set_init(bio, 0); + return 1; +} + +static int maybe_retry_write(BIO *bio, const char *in, int inl) +{ + struct maybe_retry_data_st *data = BIO_get_data(bio); + + if (data == NULL) + return -1; + + if (data->retrycnt == 0) { + BIO_set_retry_write(bio); + return -1; + } + data->retrycnt--; + + return BIO_write(BIO_next(bio), in, inl); +} + +static long maybe_retry_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + struct maybe_retry_data_st *data = BIO_get_data(bio); + + if (data == NULL) + return 0; + + switch (cmd) { + case MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT: + data->retrycnt = num; + return 1; + + case BIO_CTRL_FLUSH: + if (data->retrycnt == 0) { + BIO_set_retry_write(bio); + return -1; + } + data->retrycnt--; + /* fall through */ + default: + return BIO_ctrl(BIO_next(bio), cmd, num, ptr); + } +} + int create_ssl_ctx_pair(OSSL_LIB_CTX *libctx, const SSL_METHOD *sm, const SSL_METHOD *cm, int min_proto_version, int max_proto_version, SSL_CTX **sctx, SSL_CTX **cctx, diff --git a/test/helpers/ssltestlib.h b/test/helpers/ssltestlib.h index c513769ddd..eb54b04f2c 100644 --- a/test/helpers/ssltestlib.h +++ b/test/helpers/ssltestlib.h @@ -44,6 +44,15 @@ const BIO_METHOD *bio_s_always_retry(void); void bio_s_always_retry_free(void); void set_always_retry_err_val(int err); +/* + * Maybe retry BIO ctrls. We make them large enough to not clash with standard + * BIO ctrl codes. + */ +#define MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT (1 << 15) + +const BIO_METHOD *bio_s_maybe_retry(void); +void bio_s_maybe_retry_free(void); + /* Packet types - value 0 is reserved */ #define INJECT_PACKET 1 #define INJECT_PACKET_IGNORE_REC_SEQ 2 diff --git a/test/sslapitest.c b/test/sslapitest.c index 9539b4cf3a..2fbe76f979 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -11138,6 +11138,102 @@ end: return testresult; } +/* + * Test that receiving retries when writing application data works as expected + */ +static int test_data_retry(void) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + unsigned char inbuf[1200], outbuf[1200]; + size_t i; + BIO *tmp = NULL; + BIO *bretry = BIO_new(bio_s_maybe_retry()); + size_t written, readbytes, totread = 0; + + if (!TEST_ptr(bretry)) + goto end; + + for (i = 0; i < sizeof(inbuf); i++) + inbuf[i] = i; + memset(outbuf, 0, sizeof(outbuf)); + + if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), 0, 0, &sctx, &cctx, + cert, privkey))) + goto end; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, + NULL))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + /* Smallest possible max send fragment is 512 */ + if (!TEST_true(SSL_set_max_send_fragment(clientssl, 512))) + goto end; + + tmp = SSL_get_wbio(clientssl); + if (!TEST_ptr(tmp)) + goto end; + if (!TEST_true(BIO_up_ref(tmp))) + goto end; + BIO_push(bretry, tmp); + tmp = NULL; + SSL_set0_wbio(clientssl, bretry); + if (!BIO_up_ref(bretry)) { + bretry = NULL; + goto end; + } + + for (i = 0; i < 3; i++) { + /* We expect this call to make no progress and indicate retry */ + if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_WRITE)) + goto end; + + /* Allow one write to progess, but the next one to signal retry */ + if (!TEST_true(BIO_ctrl(bretry, MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT, 1, + NULL))) + goto end; + + if (i == 2) + break; + + /* + * This call will hopefully make progress but will still indicate retry + * because there is more data than will fit into a single record. + */ + if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_WRITE)) + goto end; + } + + /* The final call should write the last chunk of data and succeed */ + if (!TEST_true(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + /* Read all the data available */ + while (SSL_read_ex(serverssl, outbuf + totread, sizeof(outbuf) - totread, + &readbytes)) + totread += readbytes; + if (!TEST_mem_eq(inbuf, sizeof(inbuf), outbuf, totread)) + goto end; + + testresult = 1; +end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + BIO_free_all(bretry); + BIO_free(tmp); + return testresult; +} + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") int setup_tests(void) @@ -11444,6 +11540,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_version, 6); ADD_TEST(test_rstate_string); ADD_ALL_TESTS(test_handshake_retry, 16); + ADD_TEST(test_data_retry); return 1; err: @@ -11473,6 +11570,7 @@ void cleanup_tests(void) OPENSSL_free(privkey8192); bio_s_mempacket_test_free(); bio_s_always_retry_free(); + bio_s_maybe_retry_free(); OSSL_PROVIDER_unload(defctxnull); OSSL_LIB_CTX_free(libctx); } -- Gitee