From 164a541b9384cf4f2bee84c2b9b9feede6d65cca Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:37:12 +0100 Subject: [PATCH 01/81] Fix new typos found by codespell Reviewed-by: Paul Yang Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23133) --- crypto/bio/bss_dgram.c | 2 +- crypto/cmp/cmp_server.c | 2 +- crypto/evp/evp_enc.c | 2 +- crypto/modes/asm/aes-gcm-avx512.pl | 2 +- crypto/sm4/asm/vpsm4-armv8.pl | 2 +- crypto/sm4/asm/vpsm4_ex-armv8.pl | 2 +- doc/internal/man3/ossl_method_construct.pod | 2 +- include/internal/quic_srtm.h | 2 +- providers/implementations/keymgmt/dsa_kmgmt.c | 2 +- ssl/ssl_lib.c | 2 +- ssl/statem/extensions_srvr.c | 2 +- test/recipes/70-test_tls13alerts.t | 2 +- test/sslapitest.c | 4 ++-- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c index 5195634fdfa76..4dd55ab33740f 100644 --- a/crypto/bio/bss_dgram.c +++ b/crypto/bio/bss_dgram.c @@ -98,7 +98,7 @@ || M_METHOD == M_METHOD_WSARECVMSG # if defined(__APPLE__) /* - * CMSG_SPACE is not a constant expresson on OSX even though POSIX + * CMSG_SPACE is not a constant expression on OSX even though POSIX * says it's supposed to be. This should be adequate. */ # define BIO_CMSG_ALLOC_LEN 64 diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c index 4e2ca099662c1..53c41bc96eeb8 100644 --- a/crypto/cmp/cmp_server.c +++ b/crypto/cmp/cmp_server.c @@ -25,7 +25,7 @@ struct ossl_cmp_srv_ctx_st OSSL_CMP_CTX *ctx; /* CMP client context reused for transactionID etc. */ void *custom_ctx; /* application-specific server context */ int certReqId; /* of ir/cr/kur, OSSL_CMP_CERTREQID_NONE for p10cr */ - int polling; /* current tranaction is in polling mode */ + int polling; /* current transaction is in polling mode */ OSSL_CMP_SRV_cert_request_cb_t process_cert_request; OSSL_CMP_SRV_rr_cb_t process_rr; diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index a19952971271e..c289b2f7b094e 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -253,7 +253,7 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, memcpy(q++, p, sizeof(*q)); /* - * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synomym for + * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synonym for * OSSL_CIPHER_PARAM_IVLEN so both are covered here. */ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); diff --git a/crypto/modes/asm/aes-gcm-avx512.pl b/crypto/modes/asm/aes-gcm-avx512.pl index 9f9124373b4f9..e150c9aa052ca 100644 --- a/crypto/modes/asm/aes-gcm-avx512.pl +++ b/crypto/modes/asm/aes-gcm-avx512.pl @@ -2007,7 +2007,7 @@ sub INITIAL_BLOCKS_PARTIAL_GHASH { my $ZT8 = $_[20]; # [clobbered] ZMM temporary my $PBLOCK_LEN = $_[21]; # [in] partial block length my $GH = $_[22]; # [in] ZMM with hi product part - my $GM = $_[23]; # [in] ZMM with mid prodcut part + my $GM = $_[23]; # [in] ZMM with mid product part my $GL = $_[24]; # [in] ZMM with lo product part my $label_suffix = $label_count++; diff --git a/crypto/sm4/asm/vpsm4-armv8.pl b/crypto/sm4/asm/vpsm4-armv8.pl index ee96046b957db..eae3704992c55 100755 --- a/crypto/sm4/asm/vpsm4-armv8.pl +++ b/crypto/sm4/asm/vpsm4-armv8.pl @@ -937,7 +937,7 @@ () $code.=<<___; ld1 {$ivec1.4s},[$ivp] ld1 {@datax[0].4s,@datax[1].4s,@datax[2].4s,@datax[3].4s},[$inp],#64 - // note ivec1 and vtmpx[3] are resuing the same register + // note ivec1 and vtmpx[3] are reusing the same register // care needs to be taken to avoid conflict eor @vtmp[0].16b,@vtmp[0].16b,$ivec1.16b ld1 {@vtmpx[0].4s,@vtmpx[1].4s,@vtmpx[2].4s,@vtmpx[3].4s},[$inp],#64 diff --git a/crypto/sm4/asm/vpsm4_ex-armv8.pl b/crypto/sm4/asm/vpsm4_ex-armv8.pl index 27dd25aa539ed..b7f1a662228a1 100644 --- a/crypto/sm4/asm/vpsm4_ex-armv8.pl +++ b/crypto/sm4/asm/vpsm4_ex-armv8.pl @@ -927,7 +927,7 @@ () $code.=<<___; ld1 {$ivec1.4s},[$ivp] ld1 {@datax[0].4s,@datax[1].4s,@datax[2].4s,@datax[3].4s},[$inp],#64 - // note ivec1 and vtmpx[3] are resuing the same register + // note ivec1 and vtmpx[3] are reusing the same register // care needs to be taken to avoid conflict eor @vtmp[0].16b,@vtmp[0].16b,$ivec1.16b ld1 {@vtmpx[0].4s,@vtmpx[1].4s,@vtmpx[2].4s,@vtmpx[3].4s},[$inp],#64 diff --git a/doc/internal/man3/ossl_method_construct.pod b/doc/internal/man3/ossl_method_construct.pod index 3683798b06b49..603930dc1f694 100644 --- a/doc/internal/man3/ossl_method_construct.pod +++ b/doc/internal/man3/ossl_method_construct.pod @@ -93,7 +93,7 @@ This default store should be stored in the library context I. The method to be looked up should be identified with data found in I (which is the I that was passed to ossl_construct_method()). In other words, the ossl_method_construct() caller is entirely responsible -for ensuring the necesssary data is made available. +for ensuring the necessary data is made available. Optionally, I may be given as a search criterion, to narrow down the search of a method belonging to just one provider. diff --git a/include/internal/quic_srtm.h b/include/internal/quic_srtm.h index 830c3992757a0..d60c285e22950 100644 --- a/include/internal/quic_srtm.h +++ b/include/internal/quic_srtm.h @@ -26,7 +26,7 @@ * The stateless reset token manager is responsible for mapping stateless reset * tokens to connections. It is used to identify stateless reset tokens in * incoming packets. In this regard it can be considered an alternate "routing" - * mechanism for incoming packets, and is somewhat analagous with the LCIDM, + * mechanism for incoming packets, and is somewhat analogous with the LCIDM, * except that it uses SRTs to route rather than DCIDs. * * The SRTM specifically stores a bidirectional mapping of the form diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c index 3fdc78432b8e1..88a2feda572a5 100644 --- a/providers/implementations/keymgmt/dsa_kmgmt.c +++ b/providers/implementations/keymgmt/dsa_kmgmt.c @@ -479,7 +479,7 @@ static int dsa_gen_set_params(void *genctx, const OSSL_PARAM params[]) } /* - * Ony assign context gen_type if it was set by dsa_gen_type_name2id + * Only assign context gen_type if it was set by dsa_gen_type_name2id * must be in range: * DSA_PARAMGEN_TYPE_FIPS_186_4 <= gen_type <= DSA_PARAMGEN_TYPE_FIPS_DEFAULT */ diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index cf59d2dfa5726..13326d89256ff 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -343,7 +343,7 @@ static int dane_tlsa_add(SSL_DANE *dane, /* * The Full(0) certificate decodes to a seemingly valid X.509 * object with a plausible key, so the TLSA record is well - * formed. However, we don't actually need the certifiate for + * formed. However, we don't actually need the certificate for * usages PKIX-EE(1) or DANE-EE(3), because at least the EE * certificate is always presented by the peer. We discard the * certificate, and just use the TLSA data as an opaque blob diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index c4287bd853c1e..21db977c88f3d 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -582,7 +582,7 @@ int tls_parse_ctos_psk_kex_modes(SSL_CONNECTION *s, PACKET *pkt, * mode. DHE PSK will not be used for sure, because in any case where * it would be supported (i.e. if a key share is present), NO_DHE would * be supported as well. As the latter is preferred it would be - * choosen. By removing DHE PSK here, we don't have to deal with the + * chosen. By removing DHE PSK here, we don't have to deal with the * SSL_OP_PREFER_NO_DHE_KEX option in any other place. */ s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_KE; diff --git a/test/recipes/70-test_tls13alerts.t b/test/recipes/70-test_tls13alerts.t index e71fd23edbf13..152e6cc130dba 100644 --- a/test/recipes/70-test_tls13alerts.t +++ b/test/recipes/70-test_tls13alerts.t @@ -39,7 +39,7 @@ $proxy->filter(\&alert_filter); $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; plan tests => 1; my $alert = TLSProxy::Message->alert(); -ok(TLSProxy::Message->fail() && !$alert->server() && !$alert->encrypted(), "Client sends an unecrypted alert"); +ok(TLSProxy::Message->fail() && !$alert->server() && !$alert->encrypted(), "Client sends an unencrypted alert"); sub alert_filter { diff --git a/test/sslapitest.c b/test/sslapitest.c index e2c4563fd3fd4..021b50e8e56b8 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -5597,7 +5597,7 @@ static int test_tls13_psk(int idx) /* * Test TLS1.3 connection establishment succeeds with various configurations of * the options `SSL_OP_ALLOW_NO_DHE_KEX` and `SSL_OP_PREFER_NO_DHE_KEX`. - * The verification of whether the right KEX mode is choosen is not covered by + * The verification of whether the right KEX mode is chosen is not covered by * this test but by `test_tls13kexmodes`. * * Tests (idx & 1): Server has `SSL_OP_ALLOW_NO_DHE_KEX` set. @@ -11316,7 +11316,7 @@ static int test_data_retry(void) 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 */ + /* Allow one write to progress, but the next one to signal retry */ if (!TEST_true(BIO_ctrl(bretry, MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT, 1, NULL))) goto end; From 7deb2b433a08706337d8520793702f78765ecf90 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:06:24 +0100 Subject: [PATCH 02/81] Fix typos found by codespell in man pages Reviewed-by: Paul Yang Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23131) --- doc/man1/openssl-rand.pod.in | 2 +- doc/man3/OSSL_CMP_SRV_CTX_new.pod | 2 +- doc/man7/EVP_KDF-ARGON2.pod | 2 +- doc/man7/ossl-guide-tls-client-block.pod | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/man1/openssl-rand.pod.in b/doc/man1/openssl-rand.pod.in index d4427a67246ce..7c07df3f147b3 100644 --- a/doc/man1/openssl-rand.pod.in +++ b/doc/man1/openssl-rand.pod.in @@ -25,7 +25,7 @@ multiple of KiB/MiB/GiB/TiB respectively. Note that suffixes are case sensitive, and that the suffixes represent binary multiples (K = 1024 bytes, M = 1024*1024 bytes, etc). -The string 'max' may be substituted for a numercial value in num, to request the +The string 'max' may be substituted for a numerical value in num, to request the maximum number of bytes the CSPRNG can produce per instantiation. Currently, this is restricted to 2^61 bytes as per NIST SP 800-90C. diff --git a/doc/man3/OSSL_CMP_SRV_CTX_new.pod b/doc/man3/OSSL_CMP_SRV_CTX_new.pod index 66d722c291ea4..d1fd7e83b1ab8 100644 --- a/doc/man3/OSSL_CMP_SRV_CTX_new.pod +++ b/doc/man3/OSSL_CMP_SRV_CTX_new.pod @@ -127,7 +127,7 @@ OSSL_CMP_SRV_CTX_init_trans() sets in I the optional callback functions for initiating delayed delivery and cleaning up a transaction. If the function is NULL then delivery of responses is never delayed. Otherwise I takes a custom server context and a request message as input. -It must return 1 if delivery of the respecive response shall be delayed, +It must return 1 if delivery of the respective response shall be delayed, 0 if not, and -1 on error. If the function is NULL then no specific cleanup is performed. Otherwise I takes a custom server context and a transaction ID pointer diff --git a/doc/man7/EVP_KDF-ARGON2.pod b/doc/man7/EVP_KDF-ARGON2.pod index e2dfb6edbf783..d41a3179b53b3 100644 --- a/doc/man7/EVP_KDF-ARGON2.pod +++ b/doc/man7/EVP_KDF-ARGON2.pod @@ -21,7 +21,7 @@ primary seek to address trade-off (side-channel) attacks. Argon2id is a hybrid construction which, in the first two slices of the first pass, generates reference addresses data-independently as in Argon2i, whereas -in later slices and next passess it generates them data-dependently as in +in later slices and next passes it generates them data-dependently as in Argon2d. Sbox-hardened version Argon2ds is not supported. diff --git a/doc/man7/ossl-guide-tls-client-block.pod b/doc/man7/ossl-guide-tls-client-block.pod index ba59bd4ab3c81..8f72fe3a1c034 100644 --- a/doc/man7/ossl-guide-tls-client-block.pod +++ b/doc/man7/ossl-guide-tls-client-block.pod @@ -348,7 +348,7 @@ connection. To send data to the server we use the L function and to receive data from the server we use the L function. In HTTP 1.0 the client always writes data first. Our HTTP request will include the hostname that -we are connecting to. For simplicitly, we write the HTTP request in three +we are connecting to. For simplicity, we write the HTTP request in three chunks. First we write the start of the request. Secondly we write the hostname we are sending the request to. Finally we send the end of the request. From f60559eb957b53d7fd5c8c9ab566fe353ea2d9f8 Mon Sep 17 00:00:00 2001 From: Vitalii Koshura Date: Mon, 25 Dec 2023 12:38:24 +0100 Subject: [PATCH 03/81] Disable building quicserver utility when configured with `no-apps` option Signed-off-by: Vitalii Koshura Reviewed-by: Paul Yang Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23149) --- CHANGES.md | 5 +++++ util/build.info | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6f7c66dbce539..43f874ff9c592 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,6 +28,11 @@ OpenSSL 3.3 ### Changes between 3.2 and 3.3 [xx XXX xxxx] + * Disable building QUIC server utility when OpenSSL is configured with + `no-apps` + + *Vitalii Koshura* + * The activate and soft_load configuration settings for providers in openssl.cnf have been updated to require a value of [1|yes|true|on] (in lower or UPPER case) to enable the setting. Conversely a value diff --git a/util/build.info b/util/build.info index cf06f15ae4f0e..e4aab44b38038 100644 --- a/util/build.info +++ b/util/build.info @@ -6,9 +6,9 @@ SCRIPTS{noinst}=wrap.pl SOURCE[wrap.pl]=wrap.pl.in DEPEND[wrap.pl]=../configdata.pm -IF[{- !$disabled{quic} && !$disabled{stdio} -}] +IF[{- !$disabled{quic} && !$disabled{stdio} && !$disabled{apps} -}] PROGRAMS{noinst}=quicserver SOURCE[quicserver]=quicserver.c -INCLUDE[quicserver]=../include ../apps/include -DEPEND[quicserver]=../libcrypto.a ../libssl.a + INCLUDE[quicserver]=../include ../apps/include + DEPEND[quicserver]=../libcrypto.a ../libssl.a ENDIF From 5a40a2728ab8d8f25f70d9c00c47676ac6e9fbca Mon Sep 17 00:00:00 2001 From: James Muir Date: Sat, 23 Dec 2023 19:51:38 -0500 Subject: [PATCH 04/81] params: drop INT_MAX checks The INT_MAX checks in param_build.c do not appear to be needed. Drop them. This was noted during the discussion for PR #22967. This makes param_build.c more consistent with params.c. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23143) --- crypto/param_build.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/crypto/param_build.c b/crypto/param_build.c index 799094da9bd54..3294045156fa9 100644 --- a/crypto/param_build.c +++ b/crypto/param_build.c @@ -49,7 +49,7 @@ struct ossl_param_bld_st { }; static OSSL_PARAM_BLD_DEF *param_push(OSSL_PARAM_BLD *bld, const char *key, - int size, size_t alloc, int type, + size_t size, size_t alloc, int type, int secure) { OSSL_PARAM_BLD_DEF *pd = OPENSSL_zalloc(sizeof(*pd)); @@ -257,10 +257,6 @@ int OSSL_PARAM_BLD_push_utf8_string(OSSL_PARAM_BLD *bld, const char *key, if (bsize == 0) bsize = strlen(buf); - if (bsize > INT_MAX) { - ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG); - return 0; - } secure = CRYPTO_secure_allocated(buf); pd = param_push(bld, key, bsize, bsize + 1, OSSL_PARAM_UTF8_STRING, secure); if (pd == NULL) @@ -276,10 +272,6 @@ int OSSL_PARAM_BLD_push_utf8_ptr(OSSL_PARAM_BLD *bld, const char *key, if (bsize == 0) bsize = strlen(buf); - if (bsize > INT_MAX) { - ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG); - return 0; - } pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_UTF8_PTR, 0); if (pd == NULL) return 0; @@ -293,10 +285,6 @@ int OSSL_PARAM_BLD_push_octet_string(OSSL_PARAM_BLD *bld, const char *key, OSSL_PARAM_BLD_DEF *pd; int secure; - if (bsize > INT_MAX) { - ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG); - return 0; - } secure = CRYPTO_secure_allocated(buf); pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_OCTET_STRING, secure); if (pd == NULL) @@ -310,10 +298,6 @@ int OSSL_PARAM_BLD_push_octet_ptr(OSSL_PARAM_BLD *bld, const char *key, { OSSL_PARAM_BLD_DEF *pd; - if (bsize > INT_MAX) { - ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG); - return 0; - } pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_OCTET_PTR, 0); if (pd == NULL) return 0; From bcd92754d56abbcecc207d9f8c1624b7c9bb2b07 Mon Sep 17 00:00:00 2001 From: James Muir Date: Sat, 23 Dec 2023 17:03:21 -0500 Subject: [PATCH 05/81] demos: fix cert scripts set LD_LIBRARY_PATH so the correct libs can be found. Testing: cd demos/certs && sh mkcerts.sh cd demos/certs/apps && sh -x mkacerts.sh Reviewed-by: Neil Horman Reviewed-by: Paul Yang Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23142) --- demos/certs/apps/mkacerts.sh | 32 +++++++++++--------- demos/certs/apps/mkxcerts.sh | 22 +++++++++----- demos/certs/mkcerts.sh | 57 ++++++++++++++++++++---------------- demos/certs/ocspquery.sh | 17 +++++++---- demos/certs/ocsprun.sh | 11 +++++-- 5 files changed, 84 insertions(+), 55 deletions(-) diff --git a/demos/certs/apps/mkacerts.sh b/demos/certs/apps/mkacerts.sh index 70984969f44b4..996747f2cd901 100644 --- a/demos/certs/apps/mkacerts.sh +++ b/demos/certs/apps/mkacerts.sh @@ -2,38 +2,42 @@ # Recreate the demo certificates in the apps directory. -OPENSSL=openssl +opensslcmd() { + LD_LIBRARY_PATH=../../.. ../../../apps/openssl $@ +} + +opensslcmd version # Root CA: create certificate directly -CN="OpenSSL Test Root CA" $OPENSSL req -config apps.cnf -x509 -nodes \ +CN="OpenSSL Test Root CA" opensslcmd req -config apps.cnf -x509 -nodes \ -keyout root.pem -out root.pem -key rootkey.pem -new -days 3650 # Intermediate CA: request first -CN="OpenSSL Test Intermediate CA" $OPENSSL req -config apps.cnf -nodes \ +CN="OpenSSL Test Intermediate CA" opensslcmd req -config apps.cnf -nodes \ -key intkey.pem -out intreq.pem -new # Sign request: CA extensions -$OPENSSL x509 -req -in intreq.pem -CA root.pem -CAkey rootkey.pem -days 3630 \ +opensslcmd x509 -req -in intreq.pem -CA root.pem -CAkey rootkey.pem -days 3630 \ -extfile apps.cnf -extensions v3_ca -CAcreateserial -out intca.pem # Client certificate: request first -CN="Test Client Cert" $OPENSSL req -config apps.cnf -nodes \ +CN="Test Client Cert" opensslcmd req -config apps.cnf -nodes \ -key ckey.pem -out creq.pem -new # Sign using intermediate CA -$OPENSSL x509 -req -in creq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in creq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile apps.cnf -extensions usr_cert -CAcreateserial | \ - $OPENSSL x509 -nameopt oneline -subject -issuer >client.pem + opensslcmd x509 -nameopt oneline -subject -issuer >client.pem # Server certificate: request first -CN="Test Server Cert" $OPENSSL req -config apps.cnf -nodes \ +CN="Test Server Cert" opensslcmd req -config apps.cnf -nodes \ -key skey.pem -out sreq.pem -new # Sign using intermediate CA -$OPENSSL x509 -req -in sreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in sreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile apps.cnf -extensions usr_cert -CAcreateserial | \ - $OPENSSL x509 -nameopt oneline -subject -issuer >server.pem + opensslcmd x509 -nameopt oneline -subject -issuer >server.pem # Server certificate #2: request first -CN="Test Server Cert #2" $OPENSSL req -config apps.cnf -nodes \ +CN="Test Server Cert #2" opensslcmd req -config apps.cnf -nodes \ -key skey2.pem -out sreq2.pem -new # Sign using intermediate CA -$OPENSSL x509 -req -in sreq2.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in sreq2.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile apps.cnf -extensions usr_cert -CAcreateserial | \ - $OPENSSL x509 -nameopt oneline -subject -issuer >server2.pem + opensslcmd x509 -nameopt oneline -subject -issuer >server2.pem # Append keys to file. @@ -41,5 +45,5 @@ cat skey.pem >>server.pem cat skey2.pem >>server2.pem cat ckey.pem >>client.pem -$OPENSSL verify -CAfile root.pem -untrusted intca.pem \ +opensslcmd verify -CAfile root.pem -untrusted intca.pem \ server2.pem server.pem client.pem diff --git a/demos/certs/apps/mkxcerts.sh b/demos/certs/apps/mkxcerts.sh index ebe1920432be2..39d45605e1fe6 100644 --- a/demos/certs/apps/mkxcerts.sh +++ b/demos/certs/apps/mkxcerts.sh @@ -1,29 +1,35 @@ +#!/bin/sh # Create certificates using various algorithms to test multi-certificate # functionality. -OPENSSL=../../../apps/openssl -CN="OpenSSL Test RSA SHA-1 cert" $OPENSSL req \ +opensslcmd() { + LD_LIBRARY_PATH=../../.. ../../../apps/openssl $@ +} + +opensslcmd version + +CN="OpenSSL Test RSA SHA-1 cert" opensslcmd req \ -config apps.cnf -extensions usr_cert -x509 -nodes \ -keyout tsha1.pem -out tsha1.pem -new -days 3650 -sha1 -CN="OpenSSL Test RSA SHA-256 cert" $OPENSSL req \ +CN="OpenSSL Test RSA SHA-256 cert" opensslcmd req \ -config apps.cnf -extensions usr_cert -x509 -nodes \ -keyout tsha256.pem -out tsha256.pem -new -days 3650 -sha256 -CN="OpenSSL Test RSA SHA-512 cert" $OPENSSL req \ +CN="OpenSSL Test RSA SHA-512 cert" opensslcmd req \ -config apps.cnf -extensions usr_cert -x509 -nodes \ -keyout tsha512.pem -out tsha512.pem -new -days 3650 -sha512 # Create EC parameters -$OPENSSL ecparam -name P-256 -out ecp256.pem -$OPENSSL ecparam -name P-384 -out ecp384.pem +opensslcmd ecparam -name P-256 -out ecp256.pem +opensslcmd ecparam -name P-384 -out ecp384.pem -CN="OpenSSL Test P-256 SHA-256 cert" $OPENSSL req \ +CN="OpenSSL Test P-256 SHA-256 cert" opensslcmd req \ -config apps.cnf -extensions ec_cert -x509 -nodes \ -nodes -keyout tecp256.pem -out tecp256.pem -newkey ec:ecp256.pem \ -days 3650 -sha256 -CN="OpenSSL Test P-384 SHA-384 cert" $OPENSSL req \ +CN="OpenSSL Test P-384 SHA-384 cert" opensslcmd req \ -config apps.cnf -extensions ec_cert -x509 -nodes \ -nodes -keyout tecp384.pem -out tecp384.pem -newkey ec:ecp384.pem \ -days 3650 -sha384 diff --git a/demos/certs/mkcerts.sh b/demos/certs/mkcerts.sh index 2d14a95989e81..1825607fa33c4 100644 --- a/demos/certs/mkcerts.sh +++ b/demos/certs/mkcerts.sh @@ -1,73 +1,78 @@ #!/bin/sh -OPENSSL=../../apps/openssl +opensslcmd() { + LD_LIBRARY_PATH=../.. ../../apps/openssl $@ +} + OPENSSL_CONF=../../apps/openssl.cnf export OPENSSL_CONF +opensslcmd version + # Root CA: create certificate directly -CN="Test Root CA" $OPENSSL req -config ca.cnf -x509 -nodes \ +CN="Test Root CA" opensslcmd req -config ca.cnf -x509 -nodes \ -keyout root.pem -out root.pem -newkey rsa:2048 -days 3650 # Intermediate CA: request first -CN="Test Intermediate CA" $OPENSSL req -config ca.cnf -nodes \ +CN="Test Intermediate CA" opensslcmd req -config ca.cnf -nodes \ -keyout intkey.pem -out intreq.pem -newkey rsa:2048 # Sign request: CA extensions -$OPENSSL x509 -req -in intreq.pem -CA root.pem -days 3600 \ +opensslcmd x509 -req -in intreq.pem -CA root.pem -days 3600 \ -extfile ca.cnf -extensions v3_ca -CAcreateserial -out intca.pem # Server certificate: create request first -CN="Test Server Cert" $OPENSSL req -config ca.cnf -nodes \ +CN="Test Server Cert" opensslcmd req -config ca.cnf -nodes \ -keyout skey.pem -out req.pem -newkey rsa:1024 # Sign request: end entity extensions -$OPENSSL x509 -req -in req.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in req.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile ca.cnf -extensions usr_cert -CAcreateserial -out server.pem # Client certificate: request first -CN="Test Client Cert" $OPENSSL req -config ca.cnf -nodes \ +CN="Test Client Cert" opensslcmd req -config ca.cnf -nodes \ -keyout ckey.pem -out creq.pem -newkey rsa:1024 # Sign using intermediate CA -$OPENSSL x509 -req -in creq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in creq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile ca.cnf -extensions usr_cert -CAcreateserial -out client.pem # Revoked certificate: request first -CN="Test Revoked Cert" $OPENSSL req -config ca.cnf -nodes \ +CN="Test Revoked Cert" opensslcmd req -config ca.cnf -nodes \ -keyout revkey.pem -out rreq.pem -newkey rsa:1024 # Sign using intermediate CA -$OPENSSL x509 -req -in rreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in rreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile ca.cnf -extensions usr_cert -CAcreateserial -out rev.pem # OCSP responder certificate: request first -CN="Test OCSP Responder Cert" $OPENSSL req -config ca.cnf -nodes \ +CN="Test OCSP Responder Cert" opensslcmd req -config ca.cnf -nodes \ -keyout respkey.pem -out respreq.pem -newkey rsa:1024 # Sign using intermediate CA and responder extensions -$OPENSSL x509 -req -in respreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ +opensslcmd x509 -req -in respreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ -extfile ca.cnf -extensions ocsp_cert -CAcreateserial -out resp.pem # Example creating a PKCS#3 DH certificate. # First DH parameters -[ -f dhp.pem ] || $OPENSSL genpkey -genparam -algorithm DH -pkeyopt dh_paramgen_prime_len:1024 -out dhp.pem +[ -f dhp.pem ] || opensslcmd genpkey -genparam -algorithm DH -pkeyopt dh_paramgen_prime_len:1024 -out dhp.pem # Now a DH private key -$OPENSSL genpkey -paramfile dhp.pem -out dhskey.pem +opensslcmd genpkey -paramfile dhp.pem -out dhskey.pem # Create DH public key file -$OPENSSL pkey -in dhskey.pem -pubout -out dhspub.pem +opensslcmd pkey -in dhskey.pem -pubout -out dhspub.pem # Certificate request, key just reuses old one as it is ignored when the # request is signed. -CN="Test Server DH Cert" $OPENSSL req -config ca.cnf -new \ +CN="Test Server DH Cert" opensslcmd req -config ca.cnf -new \ -key skey.pem -out dhsreq.pem # Sign request: end entity DH extensions -$OPENSSL x509 -req -in dhsreq.pem -CA root.pem -days 3600 \ +opensslcmd x509 -req -in dhsreq.pem -CA root.pem -days 3600 \ -force_pubkey dhspub.pem \ -extfile ca.cnf -extensions dh_cert -CAcreateserial -out dhserver.pem # DH client certificate -$OPENSSL genpkey -paramfile dhp.pem -out dhckey.pem -$OPENSSL pkey -in dhckey.pem -pubout -out dhcpub.pem -CN="Test Client DH Cert" $OPENSSL req -config ca.cnf -new \ +opensslcmd genpkey -paramfile dhp.pem -out dhckey.pem +opensslcmd pkey -in dhckey.pem -pubout -out dhcpub.pem +CN="Test Client DH Cert" opensslcmd req -config ca.cnf -new \ -key skey.pem -out dhcreq.pem -$OPENSSL x509 -req -in dhcreq.pem -CA root.pem -days 3600 \ +opensslcmd x509 -req -in dhcreq.pem -CA root.pem -days 3600 \ -force_pubkey dhcpub.pem \ -extfile ca.cnf -extensions dh_cert -CAcreateserial -out dhclient.pem @@ -78,19 +83,19 @@ $OPENSSL x509 -req -in dhcreq.pem -CA root.pem -days 3600 \ # Create initial crl number file echo 01 >crlnum.txt # Add entries for server and client certs -$OPENSSL ca -valid server.pem -keyfile root.pem -cert root.pem \ +opensslcmd ca -valid server.pem -keyfile root.pem -cert root.pem \ -config ca.cnf -md sha1 -$OPENSSL ca -valid client.pem -keyfile root.pem -cert root.pem \ +opensslcmd ca -valid client.pem -keyfile root.pem -cert root.pem \ -config ca.cnf -md sha1 -$OPENSSL ca -valid rev.pem -keyfile root.pem -cert root.pem \ +opensslcmd ca -valid rev.pem -keyfile root.pem -cert root.pem \ -config ca.cnf -md sha1 # Generate a CRL. -$OPENSSL ca -gencrl -keyfile root.pem -cert root.pem -config ca.cnf \ +opensslcmd ca -gencrl -keyfile root.pem -cert root.pem -config ca.cnf \ -md sha1 -crldays 1 -out crl1.pem # Revoke a certificate openssl ca -revoke rev.pem -crl_reason superseded \ -keyfile root.pem -cert root.pem -config ca.cnf -md sha1 # Generate another CRL -$OPENSSL ca -gencrl -keyfile root.pem -cert root.pem -config ca.cnf \ +opensslcmd ca -gencrl -keyfile root.pem -cert root.pem -config ca.cnf \ -md sha1 -crldays 1 -out crl2.pem diff --git a/demos/certs/ocspquery.sh b/demos/certs/ocspquery.sh index f664113305698..7cb8e76423bbc 100644 --- a/demos/certs/ocspquery.sh +++ b/demos/certs/ocspquery.sh @@ -1,21 +1,28 @@ +#!/bin/sh + # Example querying OpenSSL test responder. Assumes ocsprun.sh has been # called. -OPENSSL=../../apps/openssl +opensslcmd() { + LD_LIBRARY_PATH=../.. ../../apps/openssl $@ +} + OPENSSL_CONF=../../apps/openssl.cnf export OPENSSL_CONF +opensslcmd version + # Send responder queries for each certificate. echo "Requesting OCSP status for each certificate" -$OPENSSL ocsp -issuer intca.pem -cert client.pem -CAfile root.pem \ +opensslcmd ocsp -issuer intca.pem -cert client.pem -CAfile root.pem \ -url http://127.0.0.1:8888/ -$OPENSSL ocsp -issuer intca.pem -cert server.pem -CAfile root.pem \ +opensslcmd ocsp -issuer intca.pem -cert server.pem -CAfile root.pem \ -url http://127.0.0.1:8888/ -$OPENSSL ocsp -issuer intca.pem -cert rev.pem -CAfile root.pem \ +opensslcmd ocsp -issuer intca.pem -cert rev.pem -CAfile root.pem \ -url http://127.0.0.1:8888/ # One query for all three certificates. echo "Requesting OCSP status for three certificates in one request" -$OPENSSL ocsp -issuer intca.pem \ +opensslcmd ocsp -issuer intca.pem \ -cert client.pem -cert server.pem -cert rev.pem \ -CAfile root.pem -url http://127.0.0.1:8888/ diff --git a/demos/certs/ocsprun.sh b/demos/certs/ocsprun.sh index a65e5f2fd1719..77fd62fcf1bb6 100644 --- a/demos/certs/ocsprun.sh +++ b/demos/certs/ocsprun.sh @@ -1,14 +1,21 @@ +#!/bin/sh + +opensslcmd() { + LD_LIBRARY_PATH=../.. ../../apps/openssl $@ +} + # Example of running an querying OpenSSL test OCSP responder. # This assumes "mkcerts.sh" or similar has been run to set up the # necessary file structure. -OPENSSL=../../apps/openssl OPENSSL_CONF=../../apps/openssl.cnf export OPENSSL_CONF +opensslcmd version + # Run OCSP responder. PORT=8888 -$OPENSSL ocsp -port $PORT -index index.txt -CA intca.pem \ +opensslcmd ocsp -port $PORT -index index.txt -CA intca.pem \ -rsigner resp.pem -rkey respkey.pem -rother intca.pem $* From 73ebaac827180bb51ccf807673758d7d06d5db21 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 22 Dec 2023 19:28:38 +0100 Subject: [PATCH 06/81] Fix error handling in ASN1_mbstring_ncopy Sometimes the error handling returns an ASN1_STRING object in *out although that was not passed in by the caller, and sometimes the error handling deletes the ASN1_STRING but forgets to clear the *out parameter. Therefore the caller has no chance to know, if the leaked object in *out shall be deleted or not. This may cause a use-after-free error e.g. in asn1_str2type: ==63312==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000073280 at pc 0x7f2652e93b08 bp 0x7ffe0e1951c0 sp 0x7ffe0e1951b0 READ of size 8 at 0x603000073280 thread T0 #0 0x7f2652e93b07 in asn1_string_embed_free crypto/asn1/asn1_lib.c:354 #1 0x7f2652eb521a in asn1_primitive_free crypto/asn1/tasn_fre.c:204 #2 0x7f2652eb50a9 in asn1_primitive_free crypto/asn1/tasn_fre.c:199 #3 0x7f2652eb5b67 in ASN1_item_free crypto/asn1/tasn_fre.c:20 #4 0x7f2652e8e13b in asn1_str2type crypto/asn1/asn1_gen.c:740 #5 0x7f2652e8e13b in generate_v3 crypto/asn1/asn1_gen.c:137 #6 0x7f2652e9166c in ASN1_generate_v3 crypto/asn1/asn1_gen.c:92 #7 0x7f2653307b9b in do_othername crypto/x509v3/v3_alt.c:577 #8 0x7f2653307b9b in a2i_GENERAL_NAME crypto/x509v3/v3_alt.c:492 #9 0x7f26533087c2 in v2i_subject_alt crypto/x509v3/v3_alt.c:327 #10 0x7f26533107fc in do_ext_nconf crypto/x509v3/v3_conf.c:100 #11 0x7f2653310f33 in X509V3_EXT_nconf crypto/x509v3/v3_conf.c:45 #12 0x7f2653311426 in X509V3_EXT_add_nconf_sk crypto/x509v3/v3_conf.c:312 #13 0x7f265331170c in X509V3_EXT_REQ_add_nconf crypto/x509v3/v3_conf.c:360 #14 0x564ed19d5f25 in req_main apps/req.c:806 #15 0x564ed19b8de0 in do_cmd apps/openssl.c:564 #16 0x564ed1985165 in main apps/openssl.c:183 #17 0x7f2651c4a082 in __libc_start_main ../csu/libc-start.c:308 #18 0x564ed1985acd in _start (/home/ed/OPCToolboxV5/Source/Core/OpenSSL/openssl/apps/openssl+0x139acd) 0x603000073280 is located 16 bytes inside of 24-byte region [0x603000073270,0x603000073288) freed by thread T0 here: #0 0x7f265413440f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x7f265315a429 in CRYPTO_free crypto/mem.c:311 #2 0x7f265315a429 in CRYPTO_free crypto/mem.c:300 #3 0x7f2652e757b9 in ASN1_mbstring_ncopy crypto/asn1/a_mbstr.c:191 #4 0x7f2652e75ec5 in ASN1_mbstring_copy crypto/asn1/a_mbstr.c:38 #5 0x7f2652e8e227 in asn1_str2type crypto/asn1/asn1_gen.c:681 #6 0x7f2652e8e227 in generate_v3 crypto/asn1/asn1_gen.c:137 #7 0x7f2652e9166c in ASN1_generate_v3 crypto/asn1/asn1_gen.c:92 #8 0x7f2653307b9b in do_othername crypto/x509v3/v3_alt.c:577 #9 0x7f2653307b9b in a2i_GENERAL_NAME crypto/x509v3/v3_alt.c:492 #10 0x7f26533087c2 in v2i_subject_alt crypto/x509v3/v3_alt.c:327 #11 0x7f26533107fc in do_ext_nconf crypto/x509v3/v3_conf.c:100 #12 0x7f2653310f33 in X509V3_EXT_nconf crypto/x509v3/v3_conf.c:45 #13 0x7f2653311426 in X509V3_EXT_add_nconf_sk crypto/x509v3/v3_conf.c:312 #14 0x7f265331170c in X509V3_EXT_REQ_add_nconf crypto/x509v3/v3_conf.c:360 #15 0x564ed19d5f25 in req_main apps/req.c:806 #16 0x564ed19b8de0 in do_cmd apps/openssl.c:564 #17 0x564ed1985165 in main apps/openssl.c:183 #18 0x7f2651c4a082 in __libc_start_main ../csu/libc-start.c:308 previously allocated by thread T0 here: #0 0x7f2654134808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144 #1 0x7f265315a4fd in CRYPTO_malloc crypto/mem.c:221 #2 0x7f265315a4fd in CRYPTO_malloc crypto/mem.c:198 #3 0x7f265315a945 in CRYPTO_zalloc crypto/mem.c:236 #4 0x7f2652e939a4 in ASN1_STRING_type_new crypto/asn1/asn1_lib.c:341 #5 0x7f2652e74e51 in ASN1_mbstring_ncopy crypto/asn1/a_mbstr.c:150 #6 0x7f2652e75ec5 in ASN1_mbstring_copy crypto/asn1/a_mbstr.c:38 #7 0x7f2652e8e227 in asn1_str2type crypto/asn1/asn1_gen.c:681 #8 0x7f2652e8e227 in generate_v3 crypto/asn1/asn1_gen.c:137 #9 0x7f2652e9166c in ASN1_generate_v3 crypto/asn1/asn1_gen.c:92 #10 0x7f2653307b9b in do_othername crypto/x509v3/v3_alt.c:577 #11 0x7f2653307b9b in a2i_GENERAL_NAME crypto/x509v3/v3_alt.c:492 #12 0x7f26533087c2 in v2i_subject_alt crypto/x509v3/v3_alt.c:327 #13 0x7f26533107fc in do_ext_nconf crypto/x509v3/v3_conf.c:100 #14 0x7f2653310f33 in X509V3_EXT_nconf crypto/x509v3/v3_conf.c:45 #15 0x7f2653311426 in X509V3_EXT_add_nconf_sk crypto/x509v3/v3_conf.c:312 #16 0x7f265331170c in X509V3_EXT_REQ_add_nconf crypto/x509v3/v3_conf.c:360 #17 0x564ed19d5f25 in req_main apps/req.c:806 #18 0x564ed19b8de0 in do_cmd apps/openssl.c:564 #19 0x564ed1985165 in main apps/openssl.c:183 #20 0x7f2651c4a082 in __libc_start_main ../csu/libc-start.c:308 Reviewed-by: Paul Yang Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23138) --- crypto/asn1/a_mbstr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c index 7d80798655f1c..c8170e16267d4 100644 --- a/crypto/asn1/a_mbstr.c +++ b/crypto/asn1/a_mbstr.c @@ -139,7 +139,7 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, if (*out) { free_out = 0; dest = *out; - ASN1_STRING_set0(dest, NULL, 0); + ASN1_STRING_set0(dest, NULL, 0); dest->type = str_type; } else { free_out = 1; @@ -153,6 +153,10 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, /* If both the same type just copy across */ if (inform == outform) { if (!ASN1_STRING_set(dest, in, len)) { + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); return -1; } @@ -183,8 +187,10 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, break; } if ((p = OPENSSL_malloc(outlen + 1)) == NULL) { - if (free_out) + if (free_out) { ASN1_STRING_free(dest); + *out = NULL; + } return -1; } dest->length = outlen; From d32dd65053431ee744d213b336b9a03a035807e6 Mon Sep 17 00:00:00 2001 From: slontis Date: Fri, 17 Feb 2023 09:51:59 +1000 Subject: [PATCH 07/81] Fix memleak in rsa_cms_decrypt If a call to EVP_PKEY_CTX_set_rsa_mgf1_md() fails then the caller needs to free the label. Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20319) --- crypto/cms/cms_rsa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crypto/cms/cms_rsa.c b/crypto/cms/cms_rsa.c index e3e9a220fd8ed..31436d4d68723 100644 --- a/crypto/cms/cms_rsa.c +++ b/crypto/cms/cms_rsa.c @@ -99,8 +99,10 @@ static int rsa_cms_decrypt(CMS_RecipientInfo *ri) if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0) goto err; if (label != NULL - && EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0) + && EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0) { + OPENSSL_free(label); goto err; + } /* Carry on */ rv = 1; From 0c3eb31b55d3c1544e4e044c2e3c939655bac93d Mon Sep 17 00:00:00 2001 From: slontis Date: Fri, 17 Feb 2023 09:54:58 +1000 Subject: [PATCH 08/81] Limit RSA-OAEP related functions to RSA keys only Make EVP_PKEY_CTX_set_rsa_oaep_md() and EVP_PKEY_CTX_get_rsa_oaep_md_name() only work for RSA keys. Since these calls use "digest" as a OSSL_PARAM, they should not work for other key types. Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20319) --- crypto/rsa/rsa_lib.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index 9548054da7bd7..1c3b33c28b332 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -1001,6 +1001,10 @@ int EVP_PKEY_CTX_set_rsa_pss_keygen_md_name(EVP_PKEY_CTX *ctx, */ int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + /* If key type not RSA return error */ + if (!EVP_PKEY_CTX_is_a(ctx, "RSA")) + return -1; + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)(md)); } @@ -1028,6 +1032,10 @@ int EVP_PKEY_CTX_get_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, char *name, */ int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) { + /* If key type not RSA return error */ + if (!EVP_PKEY_CTX_is_a(ctx, "RSA")) + return -1; + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)md); } From 26183614ed1dc03f509f26839b8a465684ca0f84 Mon Sep 17 00:00:00 2001 From: slontis Date: Fri, 17 Feb 2023 10:00:50 +1000 Subject: [PATCH 09/81] Add missing settable entry OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS for RSA asym Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20319) --- providers/implementations/asymciphers/rsa_enc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c index 497d69edd47c5..71bfa344d4864 100644 --- a/providers/implementations/asymciphers/rsa_enc.c +++ b/providers/implementations/asymciphers/rsa_enc.c @@ -572,6 +572,7 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) static const OSSL_PARAM known_settable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0), From 1635d7a078b21d8fc3078f6115a4d8f7e18ad1ab Mon Sep 17 00:00:00 2001 From: zengwei2000 <102871671+zengwei2000@users.noreply.github.com> Date: Thu, 21 Dec 2023 08:41:57 +0000 Subject: [PATCH 10/81] ddd-02-conn-nonblocking-threads.c: Fix the leak of conn Signed-off-by: zengwei zengwei1@uniontech.com CLA: trivial Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23115) --- doc/designs/ddd/ddd-02-conn-nonblocking-threads.c | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/designs/ddd/ddd-02-conn-nonblocking-threads.c b/doc/designs/ddd/ddd-02-conn-nonblocking-threads.c index dd981c3e6643b..19d978bba078a 100644 --- a/doc/designs/ddd/ddd-02-conn-nonblocking-threads.c +++ b/doc/designs/ddd/ddd-02-conn-nonblocking-threads.c @@ -119,6 +119,7 @@ APP_CONN *new_conn(SSL_CTX *ctx, const char *hostname) if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) { /* Note: SSL_set_alpn_protos returns 1 for failure. */ BIO_free_all(out); + free(conn); return NULL; } #endif From aa3347ba9d670a747b46974ce46f2ed9ecb38662 Mon Sep 17 00:00:00 2001 From: James Muir Date: Fri, 15 Dec 2023 21:21:46 -0500 Subject: [PATCH 11/81] doc: fix "the a" typos (and other things nearby) Reviewed-by: Neil Horman Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/23068) --- doc/man1/openssl-pkeyutl.pod.in | 6 +++--- doc/man1/openssl-req.pod.in | 2 +- doc/man3/BIO_f_md.pod | 6 +++--- doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in index 1dae76cc1288b..50c2030aa353c 100644 --- a/doc/man1/openssl-pkeyutl.pod.in +++ b/doc/man1/openssl-pkeyutl.pod.in @@ -237,12 +237,12 @@ This sets the RSA padding mode. Acceptable values for I are B for PKCS#1 padding, B for no padding, B for B mode, B for X9.31 mode and B for PSS. -In PKCS#1 padding if the message digest is not set then the supplied data is +In PKCS#1 padding, if the message digest is not set, then the supplied data is signed or verified directly instead of using a B structure. If a -digest is set then the a B structure is used and its the length +digest is set, then the B structure is used and its length must correspond to the digest type. -Note, for B padding, as a protection against Bleichenbacher attack, +Note, for B padding, as a protection against the Bleichenbacher attack, the decryption will not fail in case of padding check failures. Use B and manual inspection of the decrypted message to verify if the decrypted value has correct PKCS#1 v1.5 padding. diff --git a/doc/man1/openssl-req.pod.in b/doc/man1/openssl-req.pod.in index b0b6fd25ebe70..c2232006e52c1 100644 --- a/doc/man1/openssl-req.pod.in +++ b/doc/man1/openssl-req.pod.in @@ -289,7 +289,7 @@ It is implied by the B<-CA> option. This option implies the B<-new> flag if B<-in> is not given. If an existing request is specified with the B<-in> option, it is converted -to the a certificate; otherwise a request is created from scratch. +to a certificate; otherwise a request is created from scratch. Unless specified using the B<-set_serial> option, a large random number will be used for the serial number. diff --git a/doc/man3/BIO_f_md.pod b/doc/man3/BIO_f_md.pod index c2b825e35272b..397952f05a10d 100644 --- a/doc/man3/BIO_f_md.pod +++ b/doc/man3/BIO_f_md.pod @@ -19,7 +19,7 @@ BIO_f_md, BIO_set_md, BIO_get_md, BIO_get_md_ctx - message digest BIO filter =head1 DESCRIPTION BIO_f_md() returns the message digest BIO method. This is a filter -BIO that digests any data passed through it, it is a BIO wrapper +BIO that digests any data passed through it. It is a BIO wrapper for the digest routines EVP_DigestInit(), EVP_DigestUpdate() and EVP_DigestFinal(). @@ -36,8 +36,8 @@ BIO_set_md() sets the message digest of BIO B to B: this must be called to initialize a digest BIO before any data is passed through it. It is a BIO_ctrl() macro. -BIO_get_md() places the a pointer to the digest BIOs digest method -in B, it is a BIO_ctrl() macro. +BIO_get_md() places a pointer to the digest BIOs digest method +in B. It is a BIO_ctrl() macro. BIO_get_md_ctx() returns the digest BIOs context into B. diff --git a/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod b/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod index 5d178bb8e4de8..f289383c78152 100644 --- a/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod +++ b/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod @@ -42,8 +42,8 @@ ticket construction state according to RFC5077 Section 4 such that per session state is unnecessary and a small set of cryptographic variables needs to be maintained by the callback function implementation. -In order to reuse a session, a TLS client must send the a session ticket -extension to the server. The client can only send exactly one session ticket. +In order to reuse a session, a TLS client must send the session ticket +extension to the server. The client must send exactly one session ticket. The server, through the callback function, either agrees to reuse the session ticket information or it starts a full TLS handshake to create a new session ticket. From 8a1694f22588c0777d642253ffdc307a61245d51 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 14 Dec 2023 20:53:35 +0100 Subject: [PATCH 12/81] apps: Don't print hostname on bio_out during connect. Printing the hostname on bio_out clutters the output and breaks pipe like forwarding via openssl. Print the hostname via bio_err. Fixes #23013 Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23056) --- apps/lib/s_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/lib/s_socket.c b/apps/lib/s_socket.c index 014c1c0bc0ece..ace51686addc4 100644 --- a/apps/lib/s_socket.c +++ b/apps/lib/s_socket.c @@ -208,7 +208,7 @@ int init_client(int *sock, const char *host, const char *port, hostname = BIO_ADDR_hostname_string(BIO_ADDRINFO_address(ai), 1); if (hostname != NULL) { - BIO_printf(bio_out, "Connecting to %s\n", hostname); + BIO_printf(bio_err, "Connecting to %s\n", hostname); OPENSSL_free(hostname); } /* Remove any stale errors from previous connection attempts */ From 94be985cbcc1f0a5cf4f172d4a8d06c5c623122b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 20 Dec 2023 10:01:17 -0500 Subject: [PATCH 13/81] gate calling of evp_method_id on having a non-zero name id If a name is passed to EVP__fetch of the form: name1:name2:name3 The names are parsed on the separator ':' and added to the store, but during the lookup in inner_evp_generic_fetch, the subsequent search of the store uses the full name1:name2:name3 string, which fails lookup, and causes subsequent assertion failures in evp_method_id. instead catch the failure in inner_evp_generic_fetch and return an error code if the name_id against a colon separated list of names fails. This provides a graceful error return path without asserts, and leaves room for a future feature in which such formatted names can be parsed and searched for iteratively Add a simple test to verify that providing a colon separated name results in an error indicating an invalid lookup. Reviewed-by: Tomas Mraz Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/23110) --- crypto/evp/evp_fetch.c | 21 +++++++++++++++---- .../ossl-guide-libcrypto-introduction.pod | 4 ++++ test/evp_extra_test2.c | 19 +++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index c643ae8f9a028..bd816be5f4feb 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -318,13 +318,26 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, * there is a correct name_id and meth_id, since those have * already been calculated in get_evp_method_from_store() and * put_evp_method_in_store() above. + * Note that there is a corner case here, in which, if a user + * passes a name of the form name1:name2:..., then the construction + * will create a method against all names, but the lookup will fail + * as ossl_namemap_name2num treats the name string as a single name + * rather than introducing new features where in the EVP__fetch + * parses the string and querys for each, return an error. */ if (name_id == 0) name_id = ossl_namemap_name2num(namemap, name); - meth_id = evp_method_id(name_id, operation_id); - if (name_id != 0) - ossl_method_store_cache_set(store, prov, meth_id, propq, - method, up_ref_method, free_method); + if (name_id == 0) { + ERR_raise_data(ERR_LIB_EVP, ERR_R_FETCH_FAILED, + "Algorithm %s cannot be found", name); + free_method(method); + method = NULL; + } else { + meth_id = evp_method_id(name_id, operation_id); + if (name_id != 0) + ossl_method_store_cache_set(store, prov, meth_id, propq, + method, up_ref_method, free_method); + } } /* diff --git a/doc/man7/ossl-guide-libcrypto-introduction.pod b/doc/man7/ossl-guide-libcrypto-introduction.pod index 719f947487610..33451b4873370 100644 --- a/doc/man7/ossl-guide-libcrypto-introduction.pod +++ b/doc/man7/ossl-guide-libcrypto-introduction.pod @@ -88,6 +88,10 @@ L, L and L. +Note, while providers may register algorithms against a list of names using a +string with a colon separated list of names, fetching algorithms using that +format is currently unsupported. + =item A property query string The property query string used to guide selection of the algorithm diff --git a/test/evp_extra_test2.c b/test/evp_extra_test2.c index a06bd697941e8..32ca15bc9a8ab 100644 --- a/test/evp_extra_test2.c +++ b/test/evp_extra_test2.c @@ -1326,6 +1326,24 @@ static int test_evp_pbe_alg_add(void) } #endif +/* + * Currently, EVP__fetch doesn't support + * colon separated alternative names for lookup + * so add a test here to ensure that when one is provided + * libcrypto returns an error + */ +static int evp_test_name_parsing(void) +{ + EVP_MD *md; + + if (!TEST_ptr_null(md = EVP_MD_fetch(mainctx, "SHA256:BogusName", NULL))) { + EVP_MD_free(md); + return 0; + } + + return 1; +} + int setup_tests(void) { if (!test_get_libctx(&mainctx, &nullprov, NULL, NULL, NULL)) { @@ -1334,6 +1352,7 @@ int setup_tests(void) return 0; } + ADD_TEST(evp_test_name_parsing); ADD_TEST(test_alternative_default); ADD_ALL_TESTS(test_d2i_AutoPrivateKey_ex, OSSL_NELEM(keydata)); #ifndef OPENSSL_NO_EC From d8fa4cf76308924daaf2335c6c0ff2f7334a5b26 Mon Sep 17 00:00:00 2001 From: Grant Nichol Date: Fri, 22 Dec 2023 23:46:39 -0600 Subject: [PATCH 14/81] riscv: Fix mispelling of extension test macro When refactoring the riscv extension test macros, RISCV_HAS_ZKND_AND_ZKNE was mispelled. CLA: trivial Reviewed-by: Todd Short Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23139) --- providers/implementations/ciphers/cipher_aes_xts_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/implementations/ciphers/cipher_aes_xts_hw.c b/providers/implementations/ciphers/cipher_aes_xts_hw.c index b35b71020ed90..cef1a05c59627 100644 --- a/providers/implementations/ciphers/cipher_aes_xts_hw.c +++ b/providers/implementations/ciphers/cipher_aes_xts_hw.c @@ -285,7 +285,7 @@ static const PROV_CIPHER_HW aes_xts_rv32i_zbkb_zknd_zkne = { \ # define PROV_CIPHER_HW_select_xts() \ if (RISCV_HAS_ZBKB_AND_ZKND_AND_ZKNE()) \ return &aes_xts_rv32i_zbkb_zknd_zkne; \ -if (RISCV_HAS_ZKND_ZKNE()) \ +if (RISCV_HAS_ZKND_AND_ZKNE()) \ return &aes_xts_rv32i_zknd_zkne; # else /* The generic case */ From 59b59505893a51bd52541da738693e963bef171f Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Fri, 29 Dec 2023 22:52:50 +0100 Subject: [PATCH 15/81] Set max protocol version for dtls renegotiation tests to dtls1.2 Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23168) --- test/ssl-tests/18-dtls-renegotiate.cnf | 9 +++++++++ test/ssl-tests/18-dtls-renegotiate.cnf.in | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/test/ssl-tests/18-dtls-renegotiate.cnf b/test/ssl-tests/18-dtls-renegotiate.cnf index 0f3d1eae239e2..da95793327280 100644 --- a/test/ssl-tests/18-dtls-renegotiate.cnf +++ b/test/ssl-tests/18-dtls-renegotiate.cnf @@ -23,6 +23,7 @@ client = 0-renegotiate-client-no-resume-client [0-renegotiate-client-no-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT:@SECLEVEL=0 +MaxProtocol = DTLSv1.2 Options = NoResumptionOnRenegotiation PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem @@ -51,6 +52,7 @@ client = 1-renegotiate-client-resume-client [1-renegotiate-client-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT:@SECLEVEL=0 +MaxProtocol = DTLSv1.2 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem [1-renegotiate-client-resume-client] @@ -78,6 +80,7 @@ client = 2-renegotiate-server-resume-client [2-renegotiate-server-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT:@SECLEVEL=0 +MaxProtocol = DTLSv1.2 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem [2-renegotiate-server-resume-client] @@ -105,6 +108,7 @@ client = 3-renegotiate-client-auth-require-client [3-renegotiate-client-auth-require-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT:@SECLEVEL=0 +MaxProtocol = DTLSv1.2 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem VerifyMode = Require @@ -136,6 +140,7 @@ client = 4-renegotiate-client-auth-once-client [4-renegotiate-client-auth-once-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT:@SECLEVEL=0 +MaxProtocol = DTLSv1.2 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem VerifyMode = Once @@ -172,6 +177,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem [5-renegotiate-aead-to-non-aead-client] CipherString = AES128-GCM-SHA256 +MaxProtocol = DTLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer @@ -204,6 +210,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem [6-renegotiate-non-aead-to-aead-client] CipherString = AES128-SHA +MaxProtocol = DTLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer @@ -236,6 +243,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem [7-renegotiate-non-aead-to-non-aead-client] CipherString = AES128-SHA +MaxProtocol = DTLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer @@ -268,6 +276,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem [8-renegotiate-aead-to-aead-client] CipherString = AES128-GCM-SHA256 +MaxProtocol = DTLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer diff --git a/test/ssl-tests/18-dtls-renegotiate.cnf.in b/test/ssl-tests/18-dtls-renegotiate.cnf.in index dbac249f47f66..e4f7174df90e6 100644 --- a/test/ssl-tests/18-dtls-renegotiate.cnf.in +++ b/test/ssl-tests/18-dtls-renegotiate.cnf.in @@ -29,6 +29,7 @@ foreach my $sctp ("No", "Yes") { name => "renegotiate-client-no-resume".$suffix, server => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => 'DEFAULT:@SECLEVEL=0', "Options" => "NoResumptionOnRenegotiation" }, @@ -46,6 +47,7 @@ foreach my $sctp ("No", "Yes") { name => "renegotiate-client-resume".$suffix, server => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => 'DEFAULT:@SECLEVEL=0' }, client => { @@ -71,6 +73,7 @@ foreach my $sctp ("No", "Yes") { name => "renegotiate-server-resume".$suffix, server => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => 'DEFAULT:@SECLEVEL=0' }, client => { @@ -87,6 +90,7 @@ foreach my $sctp ("No", "Yes") { name => "renegotiate-client-auth-require".$suffix, server => { + "MaxProtocol" => "DTLSv1.2", "VerifyCAFile" => test_pem("root-cert.pem"), "VerifyMode" => "Require", "CipherString" => 'DEFAULT:@SECLEVEL=0' @@ -107,6 +111,7 @@ foreach my $sctp ("No", "Yes") { name => "renegotiate-client-auth-once".$suffix, server => { + "MaxProtocol" => "DTLSv1.2", "VerifyCAFile" => test_pem("root-cert.pem"), "VerifyMode" => "Once", "CipherString" => 'DEFAULT:@SECLEVEL=0' @@ -135,6 +140,7 @@ foreach my $sctp ("No", "Yes") "Options" => "NoResumptionOnRenegotiation" }, client => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => "AES128-GCM-SHA256", extra => { "RenegotiateCiphers" => "AES128-SHA" @@ -154,6 +160,7 @@ foreach my $sctp ("No", "Yes") "Options" => "NoResumptionOnRenegotiation" }, client => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => "AES128-SHA", extra => { "RenegotiateCiphers" => "AES128-GCM-SHA256" @@ -173,6 +180,7 @@ foreach my $sctp ("No", "Yes") "Options" => "NoResumptionOnRenegotiation" }, client => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => "AES128-SHA", extra => { "RenegotiateCiphers" => "AES256-SHA" @@ -192,6 +200,7 @@ foreach my $sctp ("No", "Yes") "Options" => "NoResumptionOnRenegotiation" }, client => { + "MaxProtocol" => "DTLSv1.2", "CipherString" => "AES128-GCM-SHA256", extra => { "RenegotiateCiphers" => "AES256-GCM-SHA384" From d7e707cb4983a35b1a265c6042da410d829f3b19 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 13 Dec 2023 12:21:04 +0100 Subject: [PATCH 16/81] Allow duplicate CMS attributes Fixes regression introduced with https://github.com/openssl/openssl/pull/21505 Fixes #22266 Reviewed-by: Shane Lontis Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/23029) --- crypto/cms/cms_att.c | 22 ++++++----- crypto/x509/x509_att.c | 83 +++++++++++++++++++++++++++++++++++++----- include/crypto/x509.h | 17 +++++++++ 3 files changed, 102 insertions(+), 20 deletions(-) diff --git a/crypto/cms/cms_att.c b/crypto/cms/cms_att.c index 5b99516b29a16..6c7fb349f52b6 100644 --- a/crypto/cms/cms_att.c +++ b/crypto/cms/cms_att.c @@ -12,8 +12,9 @@ #include #include #include -#include "cms_local.h" #include "internal/nelem.h" +#include "crypto/x509.h" +#include "cms_local.h" /*- * Attribute flags. @@ -94,7 +95,7 @@ X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc) int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr) { - if (X509at_add1_attr(&si->signedAttrs, attr)) + if (ossl_x509at_add1_attr(&si->signedAttrs, attr)) return 1; return 0; } @@ -103,7 +104,7 @@ int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *obj, int type, const void *bytes, int len) { - if (X509at_add1_attr_by_OBJ(&si->signedAttrs, obj, type, bytes, len)) + if (ossl_x509at_add1_attr_by_OBJ(&si->signedAttrs, obj, type, bytes, len)) return 1; return 0; } @@ -111,7 +112,7 @@ int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si, int nid, int type, const void *bytes, int len) { - if (X509at_add1_attr_by_NID(&si->signedAttrs, nid, type, bytes, len)) + if (ossl_x509at_add1_attr_by_NID(&si->signedAttrs, nid, type, bytes, len)) return 1; return 0; } @@ -120,7 +121,8 @@ int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si, const char *attrname, int type, const void *bytes, int len) { - if (X509at_add1_attr_by_txt(&si->signedAttrs, attrname, type, bytes, len)) + if (ossl_x509at_add1_attr_by_txt(&si->signedAttrs, attrname, type, bytes, + len)) return 1; return 0; } @@ -161,7 +163,7 @@ X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc) int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr) { - if (X509at_add1_attr(&si->unsignedAttrs, attr)) + if (ossl_x509at_add1_attr(&si->unsignedAttrs, attr)) return 1; return 0; } @@ -170,7 +172,7 @@ int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *obj, int type, const void *bytes, int len) { - if (X509at_add1_attr_by_OBJ(&si->unsignedAttrs, obj, type, bytes, len)) + if (ossl_x509at_add1_attr_by_OBJ(&si->unsignedAttrs, obj, type, bytes, len)) return 1; return 0; } @@ -179,7 +181,7 @@ int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si, int nid, int type, const void *bytes, int len) { - if (X509at_add1_attr_by_NID(&si->unsignedAttrs, nid, type, bytes, len)) + if (ossl_x509at_add1_attr_by_NID(&si->unsignedAttrs, nid, type, bytes, len)) return 1; return 0; } @@ -188,8 +190,8 @@ int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, const char *attrname, int type, const void *bytes, int len) { - if (X509at_add1_attr_by_txt(&si->unsignedAttrs, attrname, - type, bytes, len)) + if (ossl_x509at_add1_attr_by_txt(&si->unsignedAttrs, attrname, + type, bytes, len)) return 1; return 0; } diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c index 3878bb3ef598f..659c2f5b74349 100644 --- a/crypto/x509/x509_att.c +++ b/crypto/x509/x509_att.c @@ -79,8 +79,8 @@ X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc) return sk_X509_ATTRIBUTE_delete(x, loc); } -STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, - X509_ATTRIBUTE *attr) +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr) { X509_ATTRIBUTE *new_attr = NULL; STACK_OF(X509_ATTRIBUTE) *sk = NULL; @@ -89,10 +89,6 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); return NULL; } - if (*x != NULL && X509at_get_attr_by_OBJ(*x, attr->object, -1) != -1) { - ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); - return NULL; - } if (*x == NULL) { if ((sk = sk_X509_ATTRIBUTE_new_null()) == NULL) { @@ -119,19 +115,68 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, return NULL; } +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr) +{ + if (x == NULL || attr == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (*x != NULL && X509at_get_attr_by_OBJ(*x, attr->object, -1) != -1) { + ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); + return NULL; + } + + return ossl_x509at_add1_attr(x, attr); +} + +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, + int type, + const unsigned char *bytes, + int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + + attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len); + if (attr == NULL) + return 0; + ret = ossl_x509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, const ASN1_OBJECT *obj, int type, const unsigned char *bytes, int len) +{ + if (x == NULL || obj == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (*x != NULL && X509at_get_attr_by_OBJ(*x, obj, -1) != -1) { + ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); + return NULL; + } + + return ossl_x509at_add1_attr_by_OBJ(x, obj, type, bytes, len); +} + +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, + int len) { X509_ATTRIBUTE *attr; STACK_OF(X509_ATTRIBUTE) *ret; - attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len); + attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len); if (attr == NULL) return 0; - ret = X509at_add1_attr(x, attr); + ret = ossl_x509at_add1_attr(x, attr); X509_ATTRIBUTE_free(attr); return ret; } @@ -140,14 +185,32 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, int nid, int type, const unsigned char *bytes, int len) +{ + if (x == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (*x != NULL && X509at_get_attr_by_NID(*x, nid, -1) != -1) { + ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); + return NULL; + } + + return ossl_x509at_add1_attr_by_NID(x, nid, type, bytes, len); +} + +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, + int type, + const unsigned char *bytes, + int len) { X509_ATTRIBUTE *attr; STACK_OF(X509_ATTRIBUTE) *ret; - attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len); + attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len); if (attr == NULL) return 0; - ret = X509at_add1_attr(x, attr); + ret = ossl_x509at_add1_attr(x, attr); X509_ATTRIBUTE_free(attr); return ret; } diff --git a/include/crypto/x509.h b/include/crypto/x509.h index 5765b9f7197af..eb34a3f9a761e 100644 --- a/include/crypto/x509.h +++ b/include/crypto/x509.h @@ -371,4 +371,21 @@ int ossl_x509_check_private_key(const EVP_PKEY *k, const EVP_PKEY *pkey); int x509v3_add_len_value_uchar(const char *name, const unsigned char *value, size_t vallen, STACK_OF(CONF_VALUE) **extlist); +/* Attribute addition functions not checking for duplicate attributes */ +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, + int type, + const unsigned char *bytes, + int len); +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, + int len); +STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, + int type, + const unsigned char *bytes, + int len); #endif /* OSSL_CRYPTO_X509_H */ From f1f0731ddf6cb31d62a2c0f406b009ae9817ed7f Mon Sep 17 00:00:00 2001 From: slontis Date: Wed, 8 Nov 2023 16:14:44 +1000 Subject: [PATCH 17/81] Add missing documentation for X509_ATTRIBUTE related functions. Partial fix for #8026 Reviewed-by: Tom Cosgrove Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22656) --- crypto/x509/x509_req.c | 2 +- doc/build.info | 24 +++ doc/man3/CMS_signed_get_attr.pod | 214 +++++++++++++++++++++++++ doc/man3/EVP_PKEY_get_attr.pod | 113 +++++++++++++ doc/man3/X509_ATTRIBUTE.pod | 263 +++++++++++++++++++++++++++++++ doc/man3/X509_REQ_get_attr.pod | 111 +++++++++++++ util/missingcrypto.txt | 58 ------- util/other.syms | 1 + 8 files changed, 727 insertions(+), 59 deletions(-) create mode 100644 doc/man3/CMS_signed_get_attr.pod create mode 100644 doc/man3/EVP_PKEY_get_attr.pod create mode 100644 doc/man3/X509_ATTRIBUTE.pod create mode 100644 doc/man3/X509_REQ_get_attr.pod diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c index fa73b331a5ae3..77de85dc5b2d5 100644 --- a/crypto/x509/x509_req.c +++ b/crypto/x509/x509_req.c @@ -202,7 +202,7 @@ X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc) if (req == NULL) { ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); - return 0; + return NULL; } attr = X509at_delete_attr(req->req_info.attributes, loc); if (attr != NULL) diff --git a/doc/build.info b/doc/build.info index aec4ae616fb40..c88399a138064 100644 --- a/doc/build.info +++ b/doc/build.info @@ -855,6 +855,10 @@ DEPEND[html/man3/CMS_sign_receipt.html]=man3/CMS_sign_receipt.pod GENERATE[html/man3/CMS_sign_receipt.html]=man3/CMS_sign_receipt.pod DEPEND[man/man3/CMS_sign_receipt.3]=man3/CMS_sign_receipt.pod GENERATE[man/man3/CMS_sign_receipt.3]=man3/CMS_sign_receipt.pod +DEPEND[html/man3/CMS_signed_get_attr.html]=man3/CMS_signed_get_attr.pod +GENERATE[html/man3/CMS_signed_get_attr.html]=man3/CMS_signed_get_attr.pod +DEPEND[man/man3/CMS_signed_get_attr.3]=man3/CMS_signed_get_attr.pod +GENERATE[man/man3/CMS_signed_get_attr.3]=man3/CMS_signed_get_attr.pod DEPEND[html/man3/CMS_uncompress.html]=man3/CMS_uncompress.pod GENERATE[html/man3/CMS_uncompress.html]=man3/CMS_uncompress.pod DEPEND[man/man3/CMS_uncompress.3]=man3/CMS_uncompress.pod @@ -1263,6 +1267,10 @@ DEPEND[html/man3/EVP_PKEY_fromdata.html]=man3/EVP_PKEY_fromdata.pod GENERATE[html/man3/EVP_PKEY_fromdata.html]=man3/EVP_PKEY_fromdata.pod DEPEND[man/man3/EVP_PKEY_fromdata.3]=man3/EVP_PKEY_fromdata.pod GENERATE[man/man3/EVP_PKEY_fromdata.3]=man3/EVP_PKEY_fromdata.pod +DEPEND[html/man3/EVP_PKEY_get_attr.html]=man3/EVP_PKEY_get_attr.pod +GENERATE[html/man3/EVP_PKEY_get_attr.html]=man3/EVP_PKEY_get_attr.pod +DEPEND[man/man3/EVP_PKEY_get_attr.3]=man3/EVP_PKEY_get_attr.pod +GENERATE[man/man3/EVP_PKEY_get_attr.3]=man3/EVP_PKEY_get_attr.pod DEPEND[html/man3/EVP_PKEY_get_default_digest_nid.html]=man3/EVP_PKEY_get_default_digest_nid.pod GENERATE[html/man3/EVP_PKEY_get_default_digest_nid.html]=man3/EVP_PKEY_get_default_digest_nid.pod DEPEND[man/man3/EVP_PKEY_get_default_digest_nid.3]=man3/EVP_PKEY_get_default_digest_nid.pod @@ -2787,6 +2795,10 @@ DEPEND[html/man3/X509_ALGOR_dup.html]=man3/X509_ALGOR_dup.pod GENERATE[html/man3/X509_ALGOR_dup.html]=man3/X509_ALGOR_dup.pod DEPEND[man/man3/X509_ALGOR_dup.3]=man3/X509_ALGOR_dup.pod GENERATE[man/man3/X509_ALGOR_dup.3]=man3/X509_ALGOR_dup.pod +DEPEND[html/man3/X509_ATTRIBUTE.html]=man3/X509_ATTRIBUTE.pod +GENERATE[html/man3/X509_ATTRIBUTE.html]=man3/X509_ATTRIBUTE.pod +DEPEND[man/man3/X509_ATTRIBUTE.3]=man3/X509_ATTRIBUTE.pod +GENERATE[man/man3/X509_ATTRIBUTE.3]=man3/X509_ATTRIBUTE.pod DEPEND[html/man3/X509_CRL_get0_by_serial.html]=man3/X509_CRL_get0_by_serial.pod GENERATE[html/man3/X509_CRL_get0_by_serial.html]=man3/X509_CRL_get0_by_serial.pod DEPEND[man/man3/X509_CRL_get0_by_serial.3]=man3/X509_CRL_get0_by_serial.pod @@ -2831,6 +2843,10 @@ DEPEND[html/man3/X509_PUBKEY_new.html]=man3/X509_PUBKEY_new.pod GENERATE[html/man3/X509_PUBKEY_new.html]=man3/X509_PUBKEY_new.pod DEPEND[man/man3/X509_PUBKEY_new.3]=man3/X509_PUBKEY_new.pod GENERATE[man/man3/X509_PUBKEY_new.3]=man3/X509_PUBKEY_new.pod +DEPEND[html/man3/X509_REQ_get_attr.html]=man3/X509_REQ_get_attr.pod +GENERATE[html/man3/X509_REQ_get_attr.html]=man3/X509_REQ_get_attr.pod +DEPEND[man/man3/X509_REQ_get_attr.3]=man3/X509_REQ_get_attr.pod +GENERATE[man/man3/X509_REQ_get_attr.3]=man3/X509_REQ_get_attr.pod DEPEND[html/man3/X509_REQ_get_extensions.html]=man3/X509_REQ_get_extensions.pod GENERATE[html/man3/X509_REQ_get_extensions.html]=man3/X509_REQ_get_extensions.pod DEPEND[man/man3/X509_REQ_get_extensions.3]=man3/X509_REQ_get_extensions.pod @@ -3121,6 +3137,7 @@ html/man3/CMS_get0_type.html \ html/man3/CMS_get1_ReceiptRequest.html \ html/man3/CMS_sign.html \ html/man3/CMS_sign_receipt.html \ +html/man3/CMS_signed_get_attr.html \ html/man3/CMS_uncompress.html \ html/man3/CMS_verify.html \ html/man3/CMS_verify_receipt.html \ @@ -3223,6 +3240,7 @@ html/man3/EVP_PKEY_digestsign_supports_digest.html \ html/man3/EVP_PKEY_encapsulate.html \ html/man3/EVP_PKEY_encrypt.html \ html/man3/EVP_PKEY_fromdata.html \ +html/man3/EVP_PKEY_get_attr.html \ html/man3/EVP_PKEY_get_default_digest_nid.html \ html/man3/EVP_PKEY_get_field_type.html \ html/man3/EVP_PKEY_get_group_name.html \ @@ -3604,6 +3622,7 @@ html/man3/UI_new.html \ html/man3/X509V3_get_d2i.html \ html/man3/X509V3_set_ctx.html \ html/man3/X509_ALGOR_dup.html \ +html/man3/X509_ATTRIBUTE.html \ html/man3/X509_CRL_get0_by_serial.html \ html/man3/X509_EXTENSION_set_object.html \ html/man3/X509_LOOKUP.html \ @@ -3615,6 +3634,7 @@ html/man3/X509_NAME_get0_der.html \ html/man3/X509_NAME_get_index_by_NID.html \ html/man3/X509_NAME_print_ex.html \ html/man3/X509_PUBKEY_new.html \ +html/man3/X509_REQ_get_attr.html \ html/man3/X509_REQ_get_extensions.html \ html/man3/X509_SIG_get0.html \ html/man3/X509_STORE_CTX_get_by_subject.html \ @@ -3760,6 +3780,7 @@ man/man3/CMS_get0_type.3 \ man/man3/CMS_get1_ReceiptRequest.3 \ man/man3/CMS_sign.3 \ man/man3/CMS_sign_receipt.3 \ +man/man3/CMS_signed_get_attr.3 \ man/man3/CMS_uncompress.3 \ man/man3/CMS_verify.3 \ man/man3/CMS_verify_receipt.3 \ @@ -3862,6 +3883,7 @@ man/man3/EVP_PKEY_digestsign_supports_digest.3 \ man/man3/EVP_PKEY_encapsulate.3 \ man/man3/EVP_PKEY_encrypt.3 \ man/man3/EVP_PKEY_fromdata.3 \ +man/man3/EVP_PKEY_get_attr.3 \ man/man3/EVP_PKEY_get_default_digest_nid.3 \ man/man3/EVP_PKEY_get_field_type.3 \ man/man3/EVP_PKEY_get_group_name.3 \ @@ -4243,6 +4265,7 @@ man/man3/UI_new.3 \ man/man3/X509V3_get_d2i.3 \ man/man3/X509V3_set_ctx.3 \ man/man3/X509_ALGOR_dup.3 \ +man/man3/X509_ATTRIBUTE.3 \ man/man3/X509_CRL_get0_by_serial.3 \ man/man3/X509_EXTENSION_set_object.3 \ man/man3/X509_LOOKUP.3 \ @@ -4254,6 +4277,7 @@ man/man3/X509_NAME_get0_der.3 \ man/man3/X509_NAME_get_index_by_NID.3 \ man/man3/X509_NAME_print_ex.3 \ man/man3/X509_PUBKEY_new.3 \ +man/man3/X509_REQ_get_attr.3 \ man/man3/X509_REQ_get_extensions.3 \ man/man3/X509_SIG_get0.3 \ man/man3/X509_STORE_CTX_get_by_subject.3 \ diff --git a/doc/man3/CMS_signed_get_attr.pod b/doc/man3/CMS_signed_get_attr.pod new file mode 100644 index 0000000000000..833cfc441b935 --- /dev/null +++ b/doc/man3/CMS_signed_get_attr.pod @@ -0,0 +1,214 @@ +=pod + +=head1 NAME + +CMS_signed_get_attr_count, +CMS_signed_get_attr_by_NID, CMS_signed_get_attr_by_OBJ, CMS_signed_get_attr, +CMS_signed_delete_attr, +CMS_signed_add1_attr, CMS_signed_add1_attr_by_OBJ, +CMS_signed_add1_attr_by_NID, CMS_signed_add1_attr_by_txt, +CMS_signed_get0_data_by_OBJ, +CMS_unsigned_get_attr_count, +CMS_unsigned_get_attr_by_NID, CMS_unsigned_get_attr_by_OBJ, +CMS_unsigned_get_attr, CMS_unsigned_delete_attr, +CMS_unsigned_add1_attr, CMS_unsigned_add1_attr_by_OBJ, +CMS_unsigned_add1_attr_by_NID, CMS_unsigned_add1_attr_by_txt, +CMS_unsigned_get0_data_by_OBJ +- CMS signed and unsigned attribute functions + +=head1 SYNOPSIS + + #include + + int CMS_signed_get_attr_count(const CMS_SignerInfo *si); + int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos); + int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, const ASN1_OBJECT *obj, + int lastpos); + X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc); + X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc); + int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr); + int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len); + int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len); + int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len); + void *CMS_signed_get0_data_by_OBJ(const CMS_SignerInfo *si, + const ASN1_OBJECT *oid, + int lastpos, int type); + + int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si); + int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid, + int lastpos); + int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int lastpos); + X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc); + X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc); + int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr); + int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si, + const ASN1_OBJECT *obj, int type, + const void *bytes, int len); + int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si, + int nid, int type, + const void *bytes, int len); + int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, + const char *attrname, int type, + const void *bytes, int len); + void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, + int lastpos, int type); + +=head1 DESCRIPTION + +CMS_signerInfo contains separate attribute lists for signed and unsigned +attributes. Each CMS_signed_XXX() function is used for signed attributes, and +each CMS_unsigned_XXX() function is used for unsigned attributes. +Since the CMS_unsigned_XXX() functions work in the same way as the +CMS_signed_XXX() equivalents, only the CMS_signed_XXX() functions are +described below. + +CMS_signed_get_attr_by_OBJ() finds the location of the first matching object +I in the SignerInfo's I signed attribute list. The search starts at the +position after I. If the returned value is positive then it can be used +on the next call to CMS_signed_get_attr_by_OBJ() as the value of I in +order to iterate through the remaining attributes. I can be set to any +negative value on the first call, in order to start searching from the start of +the signed attribute list. + +CMS_signed_get_attr_by_NID() is similar to CMS_signed_get_attr_by_OBJ() except +that it passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +CMS_signed_get_attr() returns the B object at index I in the +I signed attribute list. I should be in the range from 0 to +CMS_signed_get_attr_count() - 1. + +CMS_signed_delete_attr() removes the B object at index I in +the I signed attribute list. An error occurs if the I attribute list +is NULL. + +CMS_signed_add1_attr() pushes a copy of the passed in B object +to the I signed attribute list. A new signed attribute list is created if +required. An error occurs if I is NULL. + +CMS_signed_add1_attr_by_OBJ() creates a new signed B using +X509_ATTRIBUTE_set1_object() and X509_ATTRIBUTE_set1_data() to assign a new +I with type I and data I of length I and then pushes it +to the I object's attribute list. + +CMS_signed_add1_attr_by_NID() is similar to CMS_signed_add1_attr_by_OBJ() except +that it passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +CMS_signed_add1_attr_by_txt() is similar to CMS_signed_add1_attr_by_OBJ() +except that it passes a name I associated with the object. +See for a list of SN_* names. + +CMS_signed_get0_data_by_OBJ() finds the first attribute in a I signed +attributes list that matches the I starting at index I +and returns the data retrieved from the found attributes first B +object. An error will occur if the attribute type I does not match the +type of the B object OR if I is either B or +B OR the attribute is not found. +If I is less than -1 then an error will occur if there are multiple +objects in the signed attribute list that match I. +If I is less than -2 then an error will occur if there is more than +one B object in the found signed attribute. + +Refer to L for information related to attributes. + +=head1 RETURN VALUES + +The CMS_unsigned_XXX() functions return values are similar to those of the +equivalent CMS_signed_XXX() functions. + +CMS_signed_get_attr_count() returns the number of signed attributes in the +SignerInfo I, or -1 if the signed attribute list is NULL. + +CMS_signed_get_attr_by_OBJ() returns -1 if either the signed attribute list of +I is empty OR if I is not found, otherwise it returns the location of +the I in the SignerInfo's I signed attribute list. + +CMS_signed_get_attr_by_NID() is similar to CMS_signed_get_attr_by_OBJ() except +that it returns -2 if the I is not known by OpenSSL. + +CMS_signed_get_attr() returns either a signed B or NULL on error. + +CMS_signed_delete_attr() returns either the removed signed B or +NULL if there is a error. + +CMS_signed_add1_attr(), CMS_signed_add1_attr_by_OBJ(), +CMS_signed_add1_attr_by_NID(), CMS_signed_add1_attr_by_txt(), +return 1 on success or 0 on error. + +CMS_signed_get0_data_by_OBJ() returns the data retrieved from the found +signed attributes first B object, or NULL if an error occurs. + +=head1 NOTES + +Some attributes are added automatically during the signing process. + +Calling CMS_SignerInfo_sign() adds the NID_pkcs9_signingTime signed +attribute. + +Calling CMS_final(), CMS_final_digest() or CMS_dataFinal() adds the +NID_pkcs9_messageDigest signed attribute. + +The NID_pkcs9_contentType signed attribute is always added if the +NID_pkcs9_signingTime attribute is added. + +Calling CMS_sign_ex(), CMS_sign_receipt() or CMS_add1_signer() may add +attributes depending on the flags parameter. See L for +more information. + +OpenSSL applies special rules for the following attribute NIDs: + +=over 4 + +=item CMS Signed Attributes + +NID_pkcs9_contentType +NID_pkcs9_messageDigest +NID_pkcs9_signingTime + +=item ESS Signed Attributes + +NID_id_smime_aa_signingCertificate +NID_id_smime_aa_signingCertificateV2 +NID_id_smime_aa_receiptRequest + +=item CMS Unsigned Attributes + +NID_pkcs9_countersignature + +=back + +CMS_signed_add1_attr(), CMS_signed_add1_attr_by_OBJ(), +CMS_signed_add1_attr_by_NID(), CMS_signed_add1_attr_by_txt() +and the equivalent CMS_unsigned_add1_attrXXX() functions allow +duplicate attributes to be added. The attribute rules are not checked +during these function calls, and are deferred until the sign or verify process +(i.e. during calls to any of CMS_sign_ex(), CMS_sign(), CMS_sign_receipt(), +CMS_add1_signer(), CMS_Final(), CMS_dataFinal(), CMS_final_digest(), +CMS_verify(), CMS_verify_receipt() or CMS_SignedData_verify()). + +For CMS attribute rules see RFC 5652 Section 11. +For ESS attribute rules see RFC 2634 Section 1.3.4 and RFC 5035 Section 5.4. + +=head1 SEE ALSO + +L + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/doc/man3/EVP_PKEY_get_attr.pod b/doc/man3/EVP_PKEY_get_attr.pod new file mode 100644 index 0000000000000..101677422c3c2 --- /dev/null +++ b/doc/man3/EVP_PKEY_get_attr.pod @@ -0,0 +1,113 @@ +=pod + +=head1 NAME + +EVP_PKEY_get_attr, +EVP_PKEY_get_attr_count, +EVP_PKEY_get_attr_by_NID, EVP_PKEY_get_attr_by_OBJ, +EVP_PKEY_delete_attr, +EVP_PKEY_add1_attr, +EVP_PKEY_add1_attr_by_OBJ, EVP_PKEY_add1_attr_by_NID, EVP_PKEY_add1_attr_by_txt +- EVP_PKEY B functions + +=head1 SYNOPSIS + + #include + + int EVP_PKEY_get_attr_count(const EVP_PKEY *key); + int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, int lastpos); + int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, const ASN1_OBJECT *obj, + int lastpos); + X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); + X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); + int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); + int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); + int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, + int nid, int type, + const unsigned char *bytes, int len); + int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, + const char *attrname, int type, + const unsigned char *bytes, int len); + +=head1 DESCRIPTION + +These functions are used by B. + +EVP_PKEY_get_attr_by_OBJ() finds the location of the first matching object I +in the I attribute list. The search starts at the position after I. +If the returned value is positive then it can be used on the next call to +EVP_PKEY_get_attr_by_OBJ() as the value of I in order to iterate through +the remaining attributes. I can be set to any negative value on the +first call, in order to start searching from the start of the attribute list. + +EVP_PKEY_get_attr_by_NID() is similar to EVP_PKEY_get_attr_by_OBJ() except that +it passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +EVP_PKEY_get_attr() returns the B object at index I in the +I attribute list. I should be in the range from 0 to +EVP_PKEY_get_attr_count() - 1. + +EVP_PKEY_delete_attr() removes the B object at index I in +the I attribute list. + +EVP_PKEY_add1_attr() pushes a copy of the passed in B object +to the I attribute list. A new I attribute list is created if required. +An error occurs if either I is NULL, or the attribute already exists. + +EVP_PKEY_add1_attr_by_OBJ() creates a new B using +X509_ATTRIBUTE_set1_object() and X509_ATTRIBUTE_set1_data() to assign a new +I with type I and data I of length I and then pushes it +to the I object's attribute list. If I already exists in the attribute +list then an error occurs. + +EVP_PKEY_add1_attr_by_NID() is similar to EVP_PKEY_add1_attr_by_OBJ() except +that it passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +EVP_PKEY_add1_attr_by_txt() is similar to EVP_PKEY_add1_attr_by_OBJ() except +that it passes a name I associated with the object. +See for a list of SN_* names. + +=head1 RETURN VALUES + +EVP_PKEY_get_attr_count() returns the number of attributes in the I object +attribute list or -1 if the attribute list is NULL. + +EVP_PKEY_get_attr_by_OBJ() returns -1 if either the list is empty OR the object +is not found, otherwise it returns the location of the object in the list. + +EVP_PKEY_get_attr_by_NID() is similar to EVP_PKEY_get_attr_by_OBJ(), except that +it returns -2 if the I is not known by OpenSSL. + +EVP_PKEY_get_attr() returns either a B or NULL if there is a +error. + +EVP_PKEY_delete_attr() returns either the removed B or NULL if +there is a error. + +EVP_PKEY_add1_attr(), EVP_PKEY_add1_attr_by_OBJ(), EVP_PKEY_add1_attr_by_NID() +and EVP_PKEY_add1_attr_by_txt() return 1 on success or 0 otherwise. + +=head1 NOTES + +A B object's attribute list is initially NULL. All the above functions +listed will return an error unless EVP_PKEY_add1_attr() is called. +All functions listed assume that the I is not NULL. + +=head1 SEE ALSO + +L + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/doc/man3/X509_ATTRIBUTE.pod b/doc/man3/X509_ATTRIBUTE.pod new file mode 100644 index 0000000000000..1eacf3ee3d927 --- /dev/null +++ b/doc/man3/X509_ATTRIBUTE.pod @@ -0,0 +1,263 @@ +=pod + +=head1 NAME + +X509_ATTRIBUTE, X509at_get_attr, +X509at_get_attr_count, X509at_get_attr_by_NID, X509at_get_attr_by_OBJ, +X509at_delete_attr, +X509at_add1_attr, +X509at_add1_attr_by_OBJ, X509at_add1_attr_by_NID, X509at_add1_attr_by_txt, +X509at_get0_data_by_OBJ, +X509_ATTRIBUTE_create, X509_ATTRIBUTE_create_by_NID, +X509_ATTRIBUTE_create_by_OBJ, X509_ATTRIBUTE_create_by_txt, +X509_ATTRIBUTE_set1_object, X509_ATTRIBUTE_set1_data, +X509_ATTRIBUTE_count, +X509_ATTRIBUTE_get0_data, X509_ATTRIBUTE_get0_object, X509_ATTRIBUTE_get0_type +- X509 attribute functions + +=head1 SYNOPSIS + + #include + + typedef struct x509_attributes_st X509_ATTRIBUTE; + + int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); + int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos); + int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, + const ASN1_OBJECT *obj, int lastpos); + X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc); + X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc); + STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); + STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) + **x, const ASN1_OBJECT *obj, + int type, + const unsigned char *bytes, + int len); + STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) + **x, int nid, int type, + const unsigned char *bytes, + int len); + STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) + **x, const char *attrname, + int type, + const unsigned char *bytes, + int len); + void *X509at_get0_data_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *x, + const ASN1_OBJECT *obj, int lastpos, int type); + X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value); + X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, + int len); + X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, + int atrtype, const void *data, + int len); + X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, + const unsigned char *bytes, + int len); + int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj); + int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, + const void *data, int len); + void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, int atrtype, + void *data); + int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *attr); + ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); + ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); + +=head1 DESCRIPTION + +B objects are used by many standards including X509, X509_REQ, +PKCS12, PKCS8, PKCS7 and CMS. + +The B object is used to represent the ASN.1 Attribute as defined +in RFC 5280, i.e. + + Attribute ::= SEQUENCE { + type AttributeType, + values SET OF AttributeValue } + + AttributeType ::= OBJECT IDENTIFIER + AttributeValue ::= ANY -- DEFINED BY AttributeType + +For example CMS defines the signing-time attribute as: + + id-signingTime OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs9(9) 5 } + + SigningTime ::= Time + + Time ::= CHOICE { + utcTime UTCTime, + generalizedTime GeneralizedTime } + +In OpenSSL B maps to an B object +and B maps to a list of B objects. + +The following functions are used for B objects. + +X509at_get_attr_by_OBJ() finds the location of the first matching object I +in a list of attributes I. The search starts at the position after I. +If the returned value is positive then it can be used on the next call to +X509at_get_attr_by_OBJ() as the value of I in order to iterate through +the remaining attributes. I can be set to any negative value on the +first call, in order to start searching from the start of the list. + +X509at_get_attr_by_NID() is similar to X509at_get_attr_by_OBJ() except that it +passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +X509at_get_attr() returns the B object at index I in the +list of attributes I. I should be in the range from 0 to +X509at_get_attr_count() - 1. + +X509at_delete_attr() removes the B object at index I in +the list of attributes I. + +X509at_add1_attr() pushes a copy of the passed in B object +to the list I. +Both I and I must be non NULL or an error will occur. +If I<*x> is NULL then a new list is created, otherwise it uses the +passed in list. An error will occur if an existing attribute (with the same +attribute type) already exists in the attribute list. + +X509at_add1_attr_by_OBJ() creates a new B using +X509_ATTRIBUTE_set1_object() and X509_ATTRIBUTE_set1_data() to assign a new +I with type I and data I of length I and then pushes it +to the attribute list I. Both I and I must be non NULL or an error +will occur. If I<*x> is NULL then a new attribute list is created. If I +already exists in the attribute list then an error occurs. + +X509at_add1_attr_by_NID() is similar to X509at_add1_attr_by_OBJ() except that it +passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +X509at_add1_attr_by_txt() is similar to X509at_add1_attr_by_OBJ() except that it +passes a name I associated with the object. +See for a list of SN_* names. + +X509_ATTRIBUTE_set1_object() assigns a B I +to the attribute I. If I contained an existing B then +it is freed. An error occurs if either I or I are NULL, or if +the passed in I cannot be duplicated. + +X509_ATTRIBUTE_set1_data() pushes a new B object onto the I +attributes list. The new object is assigned a copy of the data in I of +size I. +If I has flag I set then a table lookup using the +I attributes NID is used to set an B using +ASN1_STRING_set_by_NID(), and the passed in I must be in the format +required for that object type or an error will occur. +If I is not -1 then internally ASN1_STRING_type_new() is +used with the passed in I. +If I is 0 the call does nothing except return 1. + +X509_ATTRIBUTE_create() creates a new B using the I +to set the B OID and the I and I to set the +B. + +X509_ATTRIBUTE_create_by_OBJ() uses X509_ATTRIBUTE_set1_object() and +X509_ATTRIBUTE_set1_data() to assign a new I with type I and +data I of length I. If the passed in attribute I OR I<*attr> is +NULL then a new B will be returned, otherwise the passed in +B is used. Note that the ASN1_OBJECT I is pushed onto the +attributes existing list of objects, which could be an issue if the attributes + was different. + +X509_ATTRIBUTE_create_by_NID() is similar to X509_ATTRIBUTE_create_by_OBJ() +except that it passes the numerical identifier (NID) I associated with the +object. See for a list of NID_*. + +X509_ATTRIBUTE_create_by_txt() is similar to X509_ATTRIBUTE_create_by_OBJ() +except that it passes a name I associated with the +object. See for a list of SN_* names. + +X509_ATTRIBUTE_count() returns the number of B objects in an +attribute I. + +X509_ATTRIBUTE_get0_type() returns the B object at index I in +the attribute list I. I should be in the +range of 0 to X509_ATTRIBUTE_count() - 1 or an error will occur. + +X509_ATTRIBUTE_get0_data() returns the data of an B object at +index I in the attribute I. I is unused and can be set to NULL. +An error will occur if the attribute type I does not match the type of +the B object at index I OR if I is either +B or B OR if the I is not in the +range 0 to X509_ATTRIBUTE_count() - 1. + +X509at_get0_data_by_OBJ() finds the first attribute in an attribute list I +that matches the I starting at index I and returns the data +retrieved from the found attributes first B object. An error will +occur if the attribute type I does not match the type of the B +object OR if I is either B or B OR the +attribute is not found. +If I is less than -1 then an error will occur if there are multiple +objects in the list I that match I. +If I is less than -2 then an error will occur if there is more than +one B object in the found attribute. + +=head1 RETURN VALUES + +X509at_get_attr_count() returns the number of attributes in the list I or -1 +if I is NULL. + +X509at_get_attr_by_OBJ() returns -1 if either the list is empty OR the object +is not found, otherwise it returns the location of the object in the list. + +X509at_get_attr_by_NID() is similar to X509at_get_attr_by_OBJ(), except that +it returns -2 if the I is not known by OpenSSL. + +X509at_get_attr() returns either an B or NULL if there is a error. + +X509at_delete_attr() returns either the removed B or NULL if +there is a error. + +X509_ATTRIBUTE_count() returns -1 on error, otherwise it returns the number +of B elements. + +X509_ATTRIBUTE_get0_type() returns NULL on error, otherwise it returns a +B object. + +X509_ATTRIBUTE_get0_data() returns NULL if an error occurs, +otherwise it returns the data associated with an B object. + +X509_ATTRIBUTE_set1_object() and X509_ATTRIBUTE_set1_data() returns 1 on +success, or 0 otherwise. + +X509_ATTRIBUTE_create(), X509_ATTRIBUTE_create_by_OBJ(), +X509_ATTRIBUTE_create_by_NID() and X509_ATTRIBUTE_create_by_txt() return either +a B on success, or NULL if there is a error. + +X509at_add1_attr(), X509at_add1_attr_by_OBJ(), X509at_add1_attr_by_NID() and +X509at_add1_attr_by_txt() return NULL on error, otherwise they return a list +of B. + +X509at_get0_data_by_OBJ() returns the data retrieved from the found attributes +first B object, or NULL if an error occurs. + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L, +L, +L, +L, +L, + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/doc/man3/X509_REQ_get_attr.pod b/doc/man3/X509_REQ_get_attr.pod new file mode 100644 index 0000000000000..a85d8399b0daf --- /dev/null +++ b/doc/man3/X509_REQ_get_attr.pod @@ -0,0 +1,111 @@ +=pod + +=head1 NAME + +X509_REQ_get_attr_count, +X509_REQ_get_attr_by_NID, X509_REQ_get_attr_by_OBJ, X509_REQ_get_attr, +X509_REQ_delete_attr, +X509_REQ_add1_attr, X509_REQ_add1_attr_by_OBJ, X509_REQ_add1_attr_by_NID, +X509_REQ_add1_attr_by_txt +- B support for signed certificate requests + +=head1 SYNOPSIS + + #include + + int X509_REQ_get_attr_count(const X509_REQ *req); + int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos); + int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, const ASN1_OBJECT *obj, + int lastpos); + X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc); + X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc); + int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr); + int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); + int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len); + int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len); + +=head1 DESCRIPTION + +X509_REQ_get_attr_by_OBJ() finds the location of the first matching object I +in the I attribute list. The search starts at the position after I. +If the returned value is positive then it can be used on the next call to +X509_REQ_get_attr_by_OBJ() as the value of I in order to iterate through +the remaining attributes. I can be set to any negative value on the +first call, in order to start searching from the start of the attribute list. + +X509_REQ_get_attr_by_NID() is similar to X509_REQ_get_attr_by_OBJ() except that +it passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +X509_REQ_get_attr() returns the B object at index I in the +I attribute list. I should be in the range from 0 to +X509_REQ_get_attr_count() - 1. + +X509_REQ_delete_attr() removes the B object at index I in +the I objects list of attributes. An error occurs if I is NULL. + +X509_REQ_add1_attr() pushes a copy of the passed in B I<>attr> +to the I object's attribute list. An error will occur if either the +attribute list is NULL or the attribute already exists. + +X509_REQ_add1_attr_by_OBJ() creates a new B using +X509_ATTRIBUTE_set1_object() and X509_ATTRIBUTE_set1_data() to assign a new +I with type I and data I of length I and then pushes it +to the I object's attribute list. I must be non NULL or an error +will occur. If I already exists in the attribute list then an error occurs. + +X509_REQ_add1_attr_by_NID() is similar to X509_REQ_add1_attr_by_OBJ() except +that it passes the numerical identifier (NID) I associated with the object. +See for a list of NID_*. + +X509_REQ_add1_attr_by_txt() is similar to X509_REQ_add1_attr_by_OBJ() except +that it passes a name I associated with the object. +See for a list of SN_* names. + +Refer to L for information related to attributes. + +=head1 RETURN VALUES + +X509_REQ_get_attr_count() returns the number of attributes in the I object +attribute list or -1 if the attribute list is NULL. + +X509_REQ_get_attr_by_OBJ() returns -1 if either the I object's attribute +list is empty OR I is not found, otherwise it returns the location of the +I in the attribute list. + +X509_REQ_get_attr_by_NID() is similar to X509_REQ_get_attr_by_OBJ(), except that +it returns -2 if the I is not known by OpenSSL. + +X509_REQ_get_attr() returns either an B or NULL on error. + +X509_REQ_delete_attr() returns either the removed B or NULL if +there is a error. + +X509_REQ_add1_attr(), X509_REQ_add1_attr_by_OBJ(), X509_REQ_add1_attr_by_NID() +and X509_REQ_add1_attr_by_txt() return 1 on success or 0 on error. + +=head1 NOTES + +Any functions that modify the attributes (add or delete) internally set a flag +to indicate the ASN.1 encoding has been modified. + +=head1 SEE ALSO + +L + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index d6906f6ddc92d..08231eddce41d 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -326,27 +326,7 @@ CMS_digest_verify(3) CMS_is_detached(3) CMS_set1_signers_certs(3) CMS_set_detached(3) -CMS_signed_add1_attr(3) -CMS_signed_add1_attr_by_NID(3) -CMS_signed_add1_attr_by_OBJ(3) -CMS_signed_add1_attr_by_txt(3) -CMS_signed_delete_attr(3) -CMS_signed_get0_data_by_OBJ(3) -CMS_signed_get_attr(3) -CMS_signed_get_attr_by_NID(3) -CMS_signed_get_attr_by_OBJ(3) -CMS_signed_get_attr_count(3) CMS_stream(3) -CMS_unsigned_add1_attr(3) -CMS_unsigned_add1_attr_by_NID(3) -CMS_unsigned_add1_attr_by_OBJ(3) -CMS_unsigned_add1_attr_by_txt(3) -CMS_unsigned_delete_attr(3) -CMS_unsigned_get0_data_by_OBJ(3) -CMS_unsigned_get_attr(3) -CMS_unsigned_get_attr_by_NID(3) -CMS_unsigned_get_attr_by_OBJ(3) -CMS_unsigned_get_attr_count(3) CONF_dump_bio(3) CONF_dump_fp(3) CONF_free(3) @@ -588,18 +568,9 @@ EVP_PKEY_CTX_hex2ctrl(3) EVP_PKEY_CTX_set0_keygen_info(3) EVP_PKEY_CTX_set_data(3) EVP_PKEY_CTX_str2ctrl(3) -EVP_PKEY_add1_attr(3) -EVP_PKEY_add1_attr_by_NID(3) -EVP_PKEY_add1_attr_by_OBJ(3) -EVP_PKEY_add1_attr_by_txt(3) EVP_PKEY_assign(3) EVP_PKEY_decrypt_old(3) -EVP_PKEY_delete_attr(3) EVP_PKEY_encrypt_old(3) -EVP_PKEY_get_attr(3) -EVP_PKEY_get_attr_by_NID(3) -EVP_PKEY_get_attr_by_OBJ(3) -EVP_PKEY_get_attr_count(3) EVP_PKEY_save_parameters(3) EVP_add_alg_module(3) EVP_add_cipher(3) @@ -1107,17 +1078,7 @@ X509V3_set_conf_lhash(3) X509V3_set_nconf(3) X509V3_string_free(3) X509_ALGORS_it(3) -X509_ATTRIBUTE_count(3) -X509_ATTRIBUTE_create(3) -X509_ATTRIBUTE_create_by_NID(3) -X509_ATTRIBUTE_create_by_OBJ(3) -X509_ATTRIBUTE_create_by_txt(3) -X509_ATTRIBUTE_get0_data(3) -X509_ATTRIBUTE_get0_object(3) -X509_ATTRIBUTE_get0_type(3) X509_ATTRIBUTE_it(3) -X509_ATTRIBUTE_set1_data(3) -X509_ATTRIBUTE_set1_object(3) X509_CERT_AUX_it(3) X509_CINF_it(3) X509_CRL_INFO_it(3) @@ -1169,17 +1130,8 @@ X509_PURPOSE_get_id(3) X509_PURPOSE_get_trust(3) X509_PURPOSE_set(3) X509_REQ_INFO_it(3) -X509_REQ_add1_attr(3) -X509_REQ_add1_attr_by_NID(3) -X509_REQ_add1_attr_by_OBJ(3) -X509_REQ_add1_attr_by_txt(3) -X509_REQ_delete_attr(3) X509_REQ_extension_nid(3) X509_REQ_get1_email(3) -X509_REQ_get_attr(3) -X509_REQ_get_attr_by_NID(3) -X509_REQ_get_attr_by_OBJ(3) -X509_REQ_get_attr_count(3) X509_REQ_get_extension_nids(3) X509_REQ_it(3) X509_REQ_print(3) @@ -1275,16 +1227,6 @@ X509_supported_extension(3) X509_to_X509_REQ(3) X509_trust_clear(3) X509_trusted(3) -X509at_add1_attr(3) -X509at_add1_attr_by_NID(3) -X509at_add1_attr_by_OBJ(3) -X509at_add1_attr_by_txt(3) -X509at_delete_attr(3) -X509at_get0_data_by_OBJ(3) -X509at_get_attr(3) -X509at_get_attr_by_NID(3) -X509at_get_attr_by_OBJ(3) -X509at_get_attr_count(3) X509v3_addr_add_inherit(3) X509v3_addr_add_prefix(3) X509v3_addr_add_range(3) diff --git a/util/other.syms b/util/other.syms index bf7eb8b22e96a..4a4cabb273b8d 100644 --- a/util/other.syms +++ b/util/other.syms @@ -113,6 +113,7 @@ UI_METHOD datatype UI_STRING datatype UI_string_types datatype UI_string_types datatype +X509_ATTRIBUTE datatype X509_STORE_CTX_cert_crl_fn datatype X509_STORE_CTX_check_crl_fn datatype X509_STORE_CTX_check_issued_fn datatype From cf8fea86f73c4606f132133cb34c07f8dad42482 Mon Sep 17 00:00:00 2001 From: rilysh Date: Fri, 29 Dec 2023 02:30:56 -0500 Subject: [PATCH 18/81] provider-keymgmt.pod: fix typo Fix a typo from asymmmetric to asymmetric CLA: trivial Reviewed-by: Paul Yang Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23164) --- doc/man7/provider-keymgmt.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod index f8d04bfd0b374..cbbf8c8547629 100644 --- a/doc/man7/provider-keymgmt.pod +++ b/doc/man7/provider-keymgmt.pod @@ -376,7 +376,7 @@ length is specific to the key cryptosystem. The value should be the maximum size that a caller should allocate to safely store a signature (called I in L), -the result of asymmmetric encryption / decryption (I in +the result of asymmetric encryption / decryption (I in L, a derived secret (I in L, and similar data). From 8d89050f0f676b429043fd5445e5a570d54ad225 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 1 Jan 2024 11:53:50 -0500 Subject: [PATCH 19/81] validate requested key length in kdf_pbkdf1_do_derive When using pbkdf1 key deriviation, it is possible to request a key length larger than the maximum digest size a given digest can produce, leading to a read of random stack memory. fix it by returning an error if the requested key size n is larger than the EVP_MD_size of the digest Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23174) --- providers/implementations/kdfs/pbkdf1.c | 5 +++ test/evp_kdf_test.c | 50 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/providers/implementations/kdfs/pbkdf1.c b/providers/implementations/kdfs/pbkdf1.c index 6f95df071b359..4fa6afd104a26 100644 --- a/providers/implementations/kdfs/pbkdf1.c +++ b/providers/implementations/kdfs/pbkdf1.c @@ -72,6 +72,11 @@ static int kdf_pbkdf1_do_derive(const unsigned char *pass, size_t passlen, mdsize = EVP_MD_size(md_type); if (mdsize < 0) goto err; + if (n > (size_t)mdsize) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + goto err; + } + for (i = 1; i < iter; i++) { if (!EVP_DigestInit_ex(ctx, md_type, NULL)) goto err; diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 85bae39988b30..a3dd4a5b03288 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -544,6 +544,55 @@ static int test_kdf_pbkdf1(void) return ret; } +static int test_kdf_pbkdf1_key_too_long(void) +{ + int ret = 0; + EVP_KDF_CTX *kctx = NULL; + unsigned char out[EVP_MAX_MD_SIZE + 1]; + unsigned int iterations = 4096; + OSSL_LIB_CTX *libctx = NULL; + OSSL_PARAM *params = NULL; + OSSL_PROVIDER *legacyprov = NULL; + OSSL_PROVIDER *defprov = NULL; + + if (!TEST_ptr(libctx = OSSL_LIB_CTX_new())) + goto err; + + /* PBKDF1 only available in the legacy provider */ + legacyprov = OSSL_PROVIDER_load(libctx, "legacy"); + if (legacyprov == NULL) { + OSSL_LIB_CTX_free(libctx); + return TEST_skip("PBKDF1 only available in legacy provider"); + } + + if (!TEST_ptr(defprov = OSSL_PROVIDER_load(libctx, "default"))) + goto err; + + params = construct_pbkdf1_params("passwordPASSWORDpassword", "sha256", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + &iterations); + + /* + * This is the same test sequence as test_kdf_pbkdf1, but we expect + * failure here as the requested key size is longer than the digest + * can provide + */ + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname_libctx(libctx, OSSL_KDF_NAME_PBKDF1)) + || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) + || !TEST_int_eq(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0)) + goto err; + + ret = 1; +err: + EVP_KDF_CTX_free(kctx); + OPENSSL_free(params); + OSSL_PROVIDER_unload(defprov); + OSSL_PROVIDER_unload(legacyprov); + OSSL_LIB_CTX_free(libctx); + return ret; +} + static OSSL_PARAM *construct_pbkdf2_params(char *pass, char *digest, char *salt, unsigned int *iter, int *mode) { @@ -1920,6 +1969,7 @@ static int test_kdf_hmac_drbg_gettables(void) int setup_tests(void) { ADD_TEST(test_kdf_pbkdf1); + ADD_TEST(test_kdf_pbkdf1_key_too_long); #if !defined(OPENSSL_NO_CMAC) && !defined(OPENSSL_NO_CAMELLIA) ADD_TEST(test_kdf_kbkdf_6803_128); ADD_TEST(test_kdf_kbkdf_6803_256); From 6fd37948144b9f0702260fc4aae6bff325e34132 Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Thu, 28 Dec 2023 21:23:18 +0100 Subject: [PATCH 20/81] Simplify ssl protocol version comparisons. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23163) --- ssl/s3_lib.c | 12 +++--- ssl/ssl_local.h | 1 + ssl/statem/statem_clnt.c | 15 +++---- ssl/statem/statem_lib.c | 82 +++++++++++++++++------------------- ssl/t1_lib.c | 91 ++++++++++++++++++---------------------- 5 files changed, 93 insertions(+), 108 deletions(-) diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index e8ec98c221540..d1497b115bc0c 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -4287,15 +4287,15 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL_CONNECTION *s, STACK_OF(SSL_CIPHER) *cl } for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) { + int minversion, maxversion; + c = sk_SSL_CIPHER_value(prio, i); + minversion = SSL_CONNECTION_IS_DTLS(s) ? c->min_dtls : c->min_tls; + maxversion = SSL_CONNECTION_IS_DTLS(s) ? c->max_dtls : c->max_tls; /* Skip ciphers not supported by the protocol version */ - if (!SSL_CONNECTION_IS_DTLS(s) && - ((s->version < c->min_tls) || (s->version > c->max_tls))) - continue; - if (SSL_CONNECTION_IS_DTLS(s) && - (DTLS_VERSION_LT(s->version, c->min_dtls) || - DTLS_VERSION_GT(s->version, c->max_dtls))) + if (ssl_version_cmp(s, s->version, minversion) < 0 + || ssl_version_cmp(s, s->version, maxversion) > 0) continue; /* diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 164ec57b2e18c..4e99ada22cdf2 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -2629,6 +2629,7 @@ __owur int ssl3_handshake_write(SSL_CONNECTION *s); __owur int ssl_allow_compression(SSL_CONNECTION *s); +__owur int ssl_version_cmp(const SSL_CONNECTION *s, int versiona, int versionb); __owur int ssl_version_supported(const SSL_CONNECTION *s, int version, const SSL_METHOD **meth); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index caf9d7d11c012..922f8a1119e18 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -4119,15 +4119,12 @@ int ssl_cipher_list_to_bytes(SSL_CONNECTION *s, STACK_OF(SSL_CIPHER) *sk, /* Sanity check that the maximum version we offer has ciphers enabled */ if (!maxverok) { - if (SSL_CONNECTION_IS_DTLS(s)) { - if (DTLS_VERSION_GE(c->max_dtls, s->s3.tmp.max_ver) - && DTLS_VERSION_LE(c->min_dtls, s->s3.tmp.max_ver)) - maxverok = 1; - } else { - if (c->max_tls >= s->s3.tmp.max_ver - && c->min_tls <= s->s3.tmp.max_ver) - maxverok = 1; - } + int minproto = SSL_CONNECTION_IS_DTLS(s) ? c->min_dtls : c->min_tls; + int maxproto = SSL_CONNECTION_IS_DTLS(s) ? c->max_dtls : c->max_tls; + + if (ssl_version_cmp(s, maxproto, s->s3.tmp.max_ver) >= 0 + && ssl_version_cmp(s, minproto, s->s3.tmp.max_ver) <= 0) + maxverok = 1; } totlen += len; diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 5693a1269df2c..16b5f590a0b1b 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -156,17 +156,12 @@ int tls_setup_handshake(SSL_CONNECTION *s) /* Sanity check that we have MD5-SHA1 if we need it */ if (sctx->ssl_digest_methods[SSL_MD_MD5_SHA1_IDX] == NULL) { - int md5sha1_needed = 0; + int negotiated_minversion; + int md5sha1_needed_maxversion = SSL_CONNECTION_IS_DTLS(s) + ? DTLS1_VERSION : TLS1_1_VERSION; /* We don't have MD5-SHA1 - do we need it? */ - if (SSL_CONNECTION_IS_DTLS(s)) { - if (DTLS_VERSION_LE(ver_max, DTLS1_VERSION)) - md5sha1_needed = 1; - } else { - if (ver_max <= TLS1_1_VERSION) - md5sha1_needed = 1; - } - if (md5sha1_needed) { + if (ssl_version_cmp(s, ver_max, md5sha1_needed_maxversion) <= 0) { SSLfatal_data(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_NO_SUITABLE_DIGEST_ALGORITHM, "The max supported SSL/TLS version needs the" @@ -177,14 +172,12 @@ int tls_setup_handshake(SSL_CONNECTION *s) } ok = 1; + /* Don't allow TLSv1.1 or below to be negotiated */ - if (SSL_CONNECTION_IS_DTLS(s)) { - if (DTLS_VERSION_LT(ver_min, DTLS1_2_VERSION)) - ok = SSL_set_min_proto_version(ssl, DTLS1_2_VERSION); - } else { - if (ver_min < TLS1_2_VERSION) - ok = SSL_set_min_proto_version(ssl, TLS1_2_VERSION); - } + negotiated_minversion = SSL_CONNECTION_IS_DTLS(s) ? + DTLS1_2_VERSION : TLS1_2_VERSION; + if (ssl_version_cmp(s, ver_min, negotiated_minversion) < 0) + ok = SSL_set_min_proto_version(ssl, negotiated_minversion); if (!ok) { /* Shouldn't happen */ SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, ERR_R_INTERNAL_ERROR); @@ -204,16 +197,16 @@ int tls_setup_handshake(SSL_CONNECTION *s) */ for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i); + int cipher_minprotover = SSL_CONNECTION_IS_DTLS(s) + ? c->min_dtls : c->min_tls; + int cipher_maxprotover = SSL_CONNECTION_IS_DTLS(s) + ? c->max_dtls : c->max_tls; - if (SSL_CONNECTION_IS_DTLS(s)) { - if (DTLS_VERSION_GE(ver_max, c->min_dtls) && - DTLS_VERSION_LE(ver_max, c->max_dtls)) - ok = 1; - } else if (ver_max >= c->min_tls && ver_max <= c->max_tls) { + if (ssl_version_cmp(s, ver_max, cipher_minprotover) >= 0 + && ssl_version_cmp(s, ver_max, cipher_maxprotover) <= 0) { ok = 1; - } - if (ok) break; + } } if (!ok) { SSLfatal_data(s, SSL_AD_HANDSHAKE_FAILURE, @@ -1788,15 +1781,23 @@ int ssl_allow_compression(SSL_CONNECTION *s) return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL); } -static int version_cmp(const SSL_CONNECTION *s, int a, int b) +/* + * SSL/TLS/DTLS version comparison + * + * Returns + * 0 if versiona is equal to versionb + * 1 if versiona is greater than versionb + * -1 if versiona is less than versionb + */ +int ssl_version_cmp(const SSL_CONNECTION *s, int versiona, int versionb) { int dtls = SSL_CONNECTION_IS_DTLS(s); - if (a == b) + if (versiona == versionb) return 0; if (!dtls) - return a < b ? -1 : 1; - return DTLS_VERSION_LT(a, b) ? -1 : 1; + return versiona < versionb ? -1 : 1; + return DTLS_VERSION_LT(versiona, versionb) ? -1 : 1; } typedef struct { @@ -1873,12 +1874,12 @@ static int ssl_method_error(const SSL_CONNECTION *s, const SSL_METHOD *method) int version = method->version; if ((s->min_proto_version != 0 && - version_cmp(s, version, s->min_proto_version) < 0) || + ssl_version_cmp(s, version, s->min_proto_version) < 0) || ssl_security(s, SSL_SECOP_VERSION, 0, version, NULL) == 0) return SSL_R_VERSION_TOO_LOW; if (s->max_proto_version != 0 && - version_cmp(s, version, s->max_proto_version) > 0) + ssl_version_cmp(s, version, s->max_proto_version) > 0) return SSL_R_VERSION_TOO_HIGH; if ((s->options & method->mask) != 0) @@ -1966,7 +1967,7 @@ int ssl_version_supported(const SSL_CONNECTION *s, int version, switch (SSL_CONNECTION_GET_SSL(s)->method->version) { default: /* Version should match method version for non-ANY method */ - return version_cmp(s, version, s->version) == 0; + return ssl_version_cmp(s, version, s->version) == 0; case TLS_ANY_VERSION: table = tls_version_table; break; @@ -1976,10 +1977,10 @@ int ssl_version_supported(const SSL_CONNECTION *s, int version, } for (vent = table; - vent->version != 0 && version_cmp(s, version, vent->version) <= 0; + vent->version != 0 && ssl_version_cmp(s, version, vent->version) <= 0; ++vent) { if (vent->cmeth != NULL - && version_cmp(s, version, vent->version) == 0 + && ssl_version_cmp(s, version, vent->version) == 0 && ssl_method_error(s, vent->cmeth()) == 0 && (!s->server || version != TLS1_3_VERSION @@ -2153,7 +2154,7 @@ int ssl_choose_server_version(SSL_CONNECTION *s, CLIENTHELLO_MSG *hello, switch (server_version) { default: if (!SSL_CONNECTION_IS_TLS13(s)) { - if (version_cmp(s, client_version, s->version) < 0) + if (ssl_version_cmp(s, client_version, s->version) < 0) return SSL_R_WRONG_SSL_VERSION; *dgrd = DOWNGRADE_NONE; /* @@ -2210,7 +2211,7 @@ int ssl_choose_server_version(SSL_CONNECTION *s, CLIENTHELLO_MSG *hello, return SSL_R_BAD_LEGACY_VERSION; while (PACKET_get_net_2(&versionslist, &candidate_vers)) { - if (version_cmp(s, candidate_vers, best_vers) <= 0) + if (ssl_version_cmp(s, candidate_vers, best_vers) <= 0) continue; if (ssl_version_supported(s, candidate_vers, &best_method)) best_vers = candidate_vers; @@ -2245,7 +2246,7 @@ int ssl_choose_server_version(SSL_CONNECTION *s, CLIENTHELLO_MSG *hello, * If the supported versions extension isn't present, then the highest * version we can negotiate is TLSv1.2 */ - if (version_cmp(s, client_version, TLS1_3_VERSION) >= 0) + if (ssl_version_cmp(s, client_version, TLS1_3_VERSION) >= 0) client_version = TLS1_2_VERSION; /* @@ -2256,7 +2257,7 @@ int ssl_choose_server_version(SSL_CONNECTION *s, CLIENTHELLO_MSG *hello, const SSL_METHOD *method; if (vent->smeth == NULL || - version_cmp(s, client_version, vent->version) < 0) + ssl_version_cmp(s, client_version, vent->version) < 0) continue; method = vent->smeth(); if (ssl_method_error(s, method) == 0) { @@ -2344,13 +2345,8 @@ int ssl_choose_client_version(SSL_CONNECTION *s, int version, SSLfatal(s, SSL_AD_PROTOCOL_VERSION, ret); return 0; } - if (SSL_CONNECTION_IS_DTLS(s) ? DTLS_VERSION_LT(s->version, ver_min) - : s->version < ver_min) { - s->version = origv; - SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_R_UNSUPPORTED_PROTOCOL); - return 0; - } else if (SSL_CONNECTION_IS_DTLS(s) ? DTLS_VERSION_GT(s->version, ver_max) - : s->version > ver_max) { + if (ssl_version_cmp(s, s->version, ver_min) < 0 + || ssl_version_cmp(s, s->version, ver_max) > 0) { s->version = origv; SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_R_UNSUPPORTED_PROTOCOL); return 0; diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 236c1b49a7825..de82d2b33a1e6 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -849,6 +849,7 @@ int tls_valid_group(SSL_CONNECTION *s, uint16_t group_id, const TLS_GROUP_INFO *ginfo = tls1_group_id_lookup(SSL_CONNECTION_GET_CTX(s), group_id); int ret; + int group_minversion, group_maxversion; if (okfortls13 != NULL) *okfortls13 = 0; @@ -856,27 +857,22 @@ int tls_valid_group(SSL_CONNECTION *s, uint16_t group_id, if (ginfo == NULL) return 0; - if (SSL_CONNECTION_IS_DTLS(s)) { - if (ginfo->mindtls < 0 || ginfo->maxdtls < 0) - return 0; - if (ginfo->maxdtls == 0) - ret = 1; - else - ret = DTLS_VERSION_LE(minversion, ginfo->maxdtls); - if (ginfo->mindtls > 0) - ret &= DTLS_VERSION_GE(maxversion, ginfo->mindtls); - } else { - if (ginfo->mintls < 0 || ginfo->maxtls < 0) - return 0; - if (ginfo->maxtls == 0) - ret = 1; - else - ret = (minversion <= ginfo->maxtls); - if (ginfo->mintls > 0) - ret &= (maxversion >= ginfo->mintls); + group_minversion = SSL_CONNECTION_IS_DTLS(s) ? ginfo->mindtls : ginfo->mintls; + group_maxversion = SSL_CONNECTION_IS_DTLS(s) ? ginfo->maxdtls : ginfo->maxtls; + + if (group_minversion < 0 || group_maxversion < 0) + return 0; + if (group_maxversion == 0) + ret = 1; + else + ret = (ssl_version_cmp(s, minversion, group_maxversion) <= 0); + if (group_minversion > 0) + ret &= (ssl_version_cmp(s, maxversion, group_minversion) >= 0); + + if (!SSL_CONNECTION_IS_DTLS(s)) { if (ret && okfortls13 != NULL && maxversion == TLS1_3_VERSION) - *okfortls13 = (ginfo->maxtls == 0) - || (ginfo->maxtls >= TLS1_3_VERSION); + *okfortls13 = (group_maxversion == 0) + || (group_maxversion >= TLS1_3_VERSION); } ret &= !isec || strcmp(ginfo->algorithm, "EC") == 0 @@ -962,6 +958,7 @@ uint16_t tls1_shared_group(SSL_CONNECTION *s, int nmatch) for (k = 0, i = 0; i < num_pref; i++) { uint16_t id = pref[i]; const TLS_GROUP_INFO *inf; + int minversion, maxversion; if (!tls1_in_list(id, supp, num_supp) || !tls_group_allowed(s, id, SSL_SECOP_CURVE_SHARED)) @@ -969,20 +966,17 @@ uint16_t tls1_shared_group(SSL_CONNECTION *s, int nmatch) inf = tls1_group_id_lookup(ctx, id); if (!ossl_assert(inf != NULL)) return 0; - if (SSL_CONNECTION_IS_DTLS(s)) { - if (inf->maxdtls == -1) - continue; - if ((inf->mindtls != 0 && DTLS_VERSION_LT(s->version, inf->mindtls)) - || (inf->maxdtls != 0 - && DTLS_VERSION_GT(s->version, inf->maxdtls))) - continue; - } else { - if (inf->maxtls == -1) - continue; - if ((inf->mintls != 0 && s->version < inf->mintls) - || (inf->maxtls != 0 && s->version > inf->maxtls)) - continue; - } + + minversion = SSL_CONNECTION_IS_DTLS(s) + ? inf->mindtls : inf->mintls; + maxversion = SSL_CONNECTION_IS_DTLS(s) + ? inf->maxdtls : inf->maxtls; + if (maxversion == -1) + continue; + if ((minversion != 0 && ssl_version_cmp(s, s->version, minversion) < 0) + || (maxversion != 0 + && ssl_version_cmp(s, s->version, maxversion) > 0)) + continue; if (nmatch == k) return id; @@ -2060,6 +2054,9 @@ int ssl_set_client_disabled(SSL_CONNECTION *s) int ssl_cipher_disabled(const SSL_CONNECTION *s, const SSL_CIPHER *c, int op, int ecdhe) { + int minversion = SSL_CONNECTION_IS_DTLS(s) ? c->min_dtls : c->min_tls; + int maxversion = SSL_CONNECTION_IS_DTLS(s) ? c->max_dtls : c->max_tls; + if (c->algorithm_mkey & s->s3.tmp.mask_k || c->algorithm_auth & s->s3.tmp.mask_a) return 1; @@ -2077,23 +2074,17 @@ int ssl_cipher_disabled(const SSL_CONNECTION *s, const SSL_CIPHER *c, return 1; } - if (!SSL_CONNECTION_IS_DTLS(s)) { - int min_tls = c->min_tls; - - /* - * For historical reasons we will allow ECHDE to be selected by a server - * in SSLv3 if we are a client - */ - if (min_tls == TLS1_VERSION && ecdhe - && (c->algorithm_mkey & (SSL_kECDHE | SSL_kECDHEPSK)) != 0) - min_tls = SSL3_VERSION; + /* + * For historical reasons we will allow ECHDE to be selected by a server + * in SSLv3 if we are a client + */ + if (minversion == TLS1_VERSION + && ecdhe + && (c->algorithm_mkey & (SSL_kECDHE | SSL_kECDHEPSK)) != 0) + minversion = SSL3_VERSION; - if ((min_tls > s->s3.tmp.max_ver) || (c->max_tls < s->s3.tmp.min_ver)) - return 1; - } - if (SSL_CONNECTION_IS_DTLS(s) - && (DTLS_VERSION_GT(c->min_dtls, s->s3.tmp.max_ver) - || DTLS_VERSION_LT(c->max_dtls, s->s3.tmp.min_ver))) + if (ssl_version_cmp(s, minversion, s->s3.tmp.max_ver) > 0 + || ssl_version_cmp(s, maxversion, s->s3.tmp.min_ver) < 0) return 1; return !ssl_security(s, op, c->strength_bits, 0, (void *)c); From 8b9cf1bc2c3085b6e9493a057209ffd0bddf48a6 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 1 Jan 2024 09:25:03 -0500 Subject: [PATCH 21/81] cleanse stack variable in blake2[b|s] finalization If the output of a blake2[b|s] digest isn't a multipl of 8, then a stack buffer is used to compute the final output, which is left un-zeroed prior to return, allowing the potential leak of key data. Ensure that, if the stack variable is used, it gets cleared prior to return. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23173) --- providers/implementations/digests/blake2b_prov.c | 4 +++- providers/implementations/digests/blake2s_prov.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/providers/implementations/digests/blake2b_prov.c b/providers/implementations/digests/blake2b_prov.c index 970549ed0c2f4..a8b0848234bfe 100644 --- a/providers/implementations/digests/blake2b_prov.c +++ b/providers/implementations/digests/blake2b_prov.c @@ -324,8 +324,10 @@ int ossl_blake2b_final(unsigned char *md, BLAKE2B_CTX *c) for (i = 0; i < iter; ++i) store64(target + sizeof(c->h[i]) * i, c->h[i]); - if (target != md) + if (target != md) { memcpy(md, target, c->outlen); + OPENSSL_cleanse(target, sizeof(outbuffer)); + } OPENSSL_cleanse(c, sizeof(BLAKE2B_CTX)); return 1; diff --git a/providers/implementations/digests/blake2s_prov.c b/providers/implementations/digests/blake2s_prov.c index a9a8f9d048a23..e43f78aaa7381 100644 --- a/providers/implementations/digests/blake2s_prov.c +++ b/providers/implementations/digests/blake2s_prov.c @@ -314,8 +314,10 @@ int ossl_blake2s_final(unsigned char *md, BLAKE2S_CTX *c) for (i = 0; i < iter; ++i) store32(target + sizeof(c->h[i]) * i, c->h[i]); - if (target != md) + if (target != md) { memcpy(md, target, c->outlen); + OPENSSL_cleanse(target, sizeof(outbuffer)); + } OPENSSL_cleanse(c, sizeof(BLAKE2S_CTX)); return 1; From 98d6016afec4c0bc7bb8f33b5061beb8528cc74a Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 4 Dec 2023 11:16:45 +0100 Subject: [PATCH 22/81] Make OPENSSL_sk_push return only 0 or 1 Most of the callers do not actually check for the special -1 return condition because they do not pass NULL to it. It is also extremely improbable that any code depends on this -1 return value in this condition so it can be safely changed to 0 return. Reviewed-by: Matt Caswell Reviewed-by: Ben Kaduk (Merged from https://github.com/openssl/openssl/pull/22930) --- CHANGES.md | 5 +++++ crypto/stack/stack.c | 2 +- doc/man3/DEFINE_STACK_OF.pod | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 43f874ff9c592..625eacb6d40dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -41,6 +41,11 @@ OpenSSL 3.3 *Neil Horman* + * OPENSSL_sk_push() and sk__push() functions now return 0 instead of -1 + if called with a NULL stack argument. + + *Tomáš Mráz* + * In `openssl speed`, changed the default hash function used with `hmac` from `md5` to `sha256`. diff --git a/crypto/stack/stack.c b/crypto/stack/stack.c index 72e3087e89b32..05a37ed87d1cf 100644 --- a/crypto/stack/stack.c +++ b/crypto/stack/stack.c @@ -397,7 +397,7 @@ int OPENSSL_sk_find_all(OPENSSL_STACK *st, const void *data, int *pnum) int OPENSSL_sk_push(OPENSSL_STACK *st, const void *data) { if (st == NULL) - return -1; + return 0; return OPENSSL_sk_insert(st, data, st->num); } diff --git a/doc/man3/DEFINE_STACK_OF.pod b/doc/man3/DEFINE_STACK_OF.pod index 06a0256bacf10..7b3c724af21a7 100644 --- a/doc/man3/DEFINE_STACK_OF.pod +++ b/doc/man3/DEFINE_STACK_OF.pod @@ -270,7 +270,6 @@ on error. B_insert>(), B_push>() and B_unshift>() return the total number of elements in the stack and 0 if an error occurred. -B_push>() further returns -1 if I is NULL. B_set>() returns a pointer to the replacement element or NULL on error. @@ -297,6 +296,9 @@ and B_find_all>() calls are read-only and do not sort the stack. To avoid any performance implications this change introduces, B_sort>() should be called before these find operations. +Before OpenSSL 3.3.0 B_push>() returned -1 if I was NULL. It +was changed to return 0 in this condition as for other errors. + =head1 COPYRIGHT Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved. From 3348713ad390372ba5a0a0f98b46b2f637475e47 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 3 Jan 2024 11:03:03 +0000 Subject: [PATCH 23/81] Clarify the PKCS12 docs Issue #23151 asks a question about the meaning of the PKCS12 documentation. This PR attempts to clarify how friendlyName and localKeyID are added to the PKCS12 structure. Fixes #23151 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/23188) --- doc/man3/PKCS12_create.pod | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/man3/PKCS12_create.pod b/doc/man3/PKCS12_create.pod index 7f913f2fc1ad3..09fc895f18741 100644 --- a/doc/man3/PKCS12_create.pod +++ b/doc/man3/PKCS12_create.pod @@ -72,9 +72,15 @@ export grade software which could use signing only keys of arbitrary size but had restrictions on the permissible sizes of keys which could be used for encryption. -If a certificate contains an I or I then this will be -used for the corresponding B or B in the -PKCS12 structure. +If I is B and I contains an I then this will be +used for the corresponding B in the PKCS12 structure instead. +Similarly, if I is NULL and I contains a I then this will be +used for the corresponding B in the PKCS12 structure instead of the +id calculated from the I. + +For all certificates in I then if a certificate contains an I or +I then this will be used for the corresponding B or +B in the PKCS12 structure. Either I, I or both can be B to indicate that no key or certificate is required. In previous versions both had to be present or From 2995be50e8c2f2ef907866e35347be1e200558a2 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 3 Jan 2024 09:43:16 +0000 Subject: [PATCH 24/81] Correct ssl_old_test stream handling The ssl_old_test has not been fully converted to the test framework but it still reuses some test framework utilities. Notably it was creating it's own copy of the global bio_err object directly (which is normally created and owned by the test framework). This causes a problem because ever since commit 2fa9044 access to the bio_err object is controlled by a lock. Since ssl_old_test was circumventing the normal creation and destruction of bio_err, the lock was not being created resulting in a crash under certain error conditions. We fix this by creating and destroying the bio_err object using the test framework functions designed for that purpose. Fixes #23184 Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23187) --- test/ssl_old_test.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/ssl_old_test.c b/test/ssl_old_test.c index b0f4ae3ac523f..430e1801e7920 100644 --- a/test/ssl_old_test.c +++ b/test/ssl_old_test.c @@ -56,6 +56,7 @@ #endif #include #include "testutil.h" +#include "testutil/output.h" /* * Or gethostname won't be declared properly @@ -945,7 +946,8 @@ int main(int argc, char *argv[]) verbose = 0; debug = 0; - bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); + test_open_streams(); + bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT); s_cctx = SSL_CONF_CTX_new(); @@ -990,7 +992,8 @@ int main(int argc, char *argv[]) if (strcmp(*argv, "-F") == 0) { fprintf(stderr, "not compiled with FIPS support, so exiting without running.\n"); - EXIT(0); + ret = EXIT_SUCCESS; + goto end; } else if (strcmp(*argv, "-server_auth") == 0) server_auth = 1; else if (strcmp(*argv, "-client_auth") == 0) @@ -1257,7 +1260,7 @@ int main(int argc, char *argv[]) if (ssl3 + tls1 + tls1_1 + tls1_2 + dtls + dtls1 + dtls12 > 1) { fprintf(stderr, "At most one of -ssl3, -tls1, -tls1_1, -tls1_2, -dtls, -dtls1 or -dtls12 should " "be requested.\n"); - EXIT(1); + goto end; } #ifdef OPENSSL_NO_SSL3 @@ -1310,7 +1313,7 @@ int main(int argc, char *argv[]) "the test anyway (and\n-d to see what happens), " "or add one of -ssl3, -tls1, -tls1_1, -tls1_2, -dtls, -dtls1, -dtls12, -reuse\n" "to avoid protocol mismatch.\n"); - EXIT(1); + goto end; } if (print_time) { @@ -1922,7 +1925,8 @@ int main(int argc, char *argv[]) OSSL_PROVIDER_unload(thisprov); OSSL_LIB_CTX_free(libctx); - BIO_free(bio_err); + test_close_streams(); + EXIT(ret); } From 337eb99c8474ed380f3aa6fbd6b2a4ab5d39aa26 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 14 Nov 2023 06:01:51 -0500 Subject: [PATCH 25/81] Adding interop tests Fedora has some fairly nice interoperability tests that we can leverage to build a PR and test it against gnutls and nss libraries. This commit adds the interop-tests.yml ci job to do that work, and run the interop tests from beaker. Fixes #20685 Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22726) --- .github/workflows/interop-tests.yml | 50 +++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/interop-tests.yml diff --git a/.github/workflows/interop-tests.yml b/.github/workflows/interop-tests.yml new file mode 100644 index 0000000000000..952e1b7d2da10 --- /dev/null +++ b/.github/workflows/interop-tests.yml @@ -0,0 +1,50 @@ +# Notes: +# /__w/openssl is the path that github bind-mounts into the container so the ci +# filesystem for this job can be reached. Please note that any changes made to +# this job involving file system paths should be made prefixed with, or relative +# to that directory +name: Interoperability tests with GnuTLS and NSS +on: + schedule: + - cron: '0 6 * * *' +jobs: + test: + runs-on: ubuntu-22.04 + container: + image: docker.io/fedora:39 + options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + COMPONENT: [gnutls, nss] + env: + COMPONENT: ${{ matrix.COMPONENT }} + steps: + - uses: actions/checkout@v4 + - name : Install needed tools + run: | + dnf -y install perl gcc rpmdevtools dnf-utils make tmt-all beakerlib \ + fips-mode-setup crypto-policies-scripts + - name: install interop tests + run: | + cd /__w/openssl/openssl + git clone --branch=openssl --depth=1 https://gitlab.com/redhat-crypto/tests/interop.git + - name: build openssl as an rpm + run: | + mkdir -p /build/SPECS && cd /build && echo -e "%_topdir /build\n%_lto_cflags %{nil}" >~/.rpmmacros && rpmdev-setuptree + cd /build && cp /__w/openssl/openssl/interop/openssl.spec SPECS/ && \ + cd SPECS/ && source /__w/openssl/openssl/VERSION.dat && \ + sed -i "s/^Version: .*\$/Version: $MAJOR.$MINOR.$PATCH/" openssl.spec && \ + sed -i 's/^Release: .*$/Release: dev/' openssl.spec + yum-builddep -y /build/SPECS/openssl.spec # just for sure nothing is missing + mkdir -p /build/SOURCES + tar --transform "s/^__w\/openssl\/openssl/openssl-$MAJOR.$MINOR.$PATCH/" -czf /build/SOURCES/openssl-$MAJOR.$MINOR.$PATCH.tar.gz /__w/openssl/openssl/ + rpmbuild -bb /build/SPECS/openssl.spec + dnf install -y /build/RPMS/x86_64/openssl-* + - name: Run interop tests + run: | + cd interop + tmt run -av plans -n interop tests -f "tag: interop-openssl & tag: interop-$COMPONENT" provision -h local execute -h tmt --interactive + openssl version + echo "Finished - important to prevent unwanted output truncating" From 638ad52ae53ece2e870984430493e454f75d048a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 19 Dec 2023 06:15:39 -0500 Subject: [PATCH 26/81] Update workflow to use GITHUB_WORKSPACE It was pointed out the GITHUB_WORKSPACE points to the container path of the workspace, so we can use it instead of hardcoding the __w/openssl/openssl path Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22726) --- .github/workflows/interop-tests.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/interop-tests.yml b/.github/workflows/interop-tests.yml index 952e1b7d2da10..d6a17f67900c5 100644 --- a/.github/workflows/interop-tests.yml +++ b/.github/workflows/interop-tests.yml @@ -22,19 +22,21 @@ jobs: COMPONENT: ${{ matrix.COMPONENT }} steps: - uses: actions/checkout@v4 + - name: Display environment + run: export - name : Install needed tools run: | dnf -y install perl gcc rpmdevtools dnf-utils make tmt-all beakerlib \ fips-mode-setup crypto-policies-scripts - name: install interop tests run: | - cd /__w/openssl/openssl + cd ${GITHUB_WORKSPACE} git clone --branch=openssl --depth=1 https://gitlab.com/redhat-crypto/tests/interop.git - name: build openssl as an rpm run: | mkdir -p /build/SPECS && cd /build && echo -e "%_topdir /build\n%_lto_cflags %{nil}" >~/.rpmmacros && rpmdev-setuptree - cd /build && cp /__w/openssl/openssl/interop/openssl.spec SPECS/ && \ - cd SPECS/ && source /__w/openssl/openssl/VERSION.dat && \ + cd /build && cp ${GITHUB_WORKSPACE}/interop/openssl.spec SPECS/ && \ + cd SPECS/ && source ${GITHUB_WORKSPACE}/VERSION.dat && \ sed -i "s/^Version: .*\$/Version: $MAJOR.$MINOR.$PATCH/" openssl.spec && \ sed -i 's/^Release: .*$/Release: dev/' openssl.spec yum-builddep -y /build/SPECS/openssl.spec # just for sure nothing is missing From 83783dd16e767483020e5b2dc3b1c0ac26520917 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 14 Nov 2023 06:01:51 -0500 Subject: [PATCH 27/81] Adding interop tests Fedora has some fairly nice interoperability tests that we can leverage to build a PR and test it against gnutls and nss libraries. This commit adds the interop-tests.yml ci job to do that work, and run the interop tests from beaker. Fixes #20685 Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22726) --- .github/workflows/interop-tests.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/interop-tests.yml b/.github/workflows/interop-tests.yml index d6a17f67900c5..6ace6a60aa6b6 100644 --- a/.github/workflows/interop-tests.yml +++ b/.github/workflows/interop-tests.yml @@ -1,8 +1,3 @@ -# Notes: -# /__w/openssl is the path that github bind-mounts into the container so the ci -# filesystem for this job can be reached. Please note that any changes made to -# this job involving file system paths should be made prefixed with, or relative -# to that directory name: Interoperability tests with GnuTLS and NSS on: schedule: From b062a3c552bf283319dede3437598f1747730053 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 15 Dec 2023 14:35:04 -0500 Subject: [PATCH 28/81] fixup! Adding interop tests Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22726) --- .github/workflows/interop-tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/interop-tests.yml b/.github/workflows/interop-tests.yml index 6ace6a60aa6b6..d6a17f67900c5 100644 --- a/.github/workflows/interop-tests.yml +++ b/.github/workflows/interop-tests.yml @@ -1,3 +1,8 @@ +# Notes: +# /__w/openssl is the path that github bind-mounts into the container so the ci +# filesystem for this job can be reached. Please note that any changes made to +# this job involving file system paths should be made prefixed with, or relative +# to that directory name: Interoperability tests with GnuTLS and NSS on: schedule: From bac7e687d71b124b09ad6ad3e15be9b38c08a1ba Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 2 Jan 2024 15:48:00 -0500 Subject: [PATCH 29/81] Validate config options during x509 extension creation There are several points during x509 extension creation which rely on configuration options which may have been incorrectly parsed due to invalid settings. Preform a value check for null in those locations to avoid various crashes/undefined behaviors Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23183) --- crypto/x509/v3_addr.c | 4 ++++ crypto/x509/v3_asid.c | 5 +++++ crypto/x509/v3_crld.c | 5 +++++ crypto/x509/v3_ist.c | 16 ++++++++++++---- test/invalid-x509.cnf | 6 ++++++ test/recipes/25-test_x509.t | 10 +++++++++- 6 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 test/invalid-x509.cnf diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c index da9604cf963a3..bd937388f365f 100644 --- a/crypto/x509/v3_addr.c +++ b/crypto/x509/v3_addr.c @@ -988,6 +988,10 @@ static void *v2i_IPAddrBlocks(const struct v3_ext_method *method, * the other input values. */ if (safi != NULL) { + if (val->value == NULL) { + ERR_raise(ERR_LIB_X509V3, X509V3_R_MISSING_VALUE); + goto err; + } *safi = strtoul(val->value, &t, 0); t += strspn(t, " \t"); if (*safi > 0xFF || *t++ != ':') { diff --git a/crypto/x509/v3_asid.c b/crypto/x509/v3_asid.c index 251243b723732..1cb892df67002 100644 --- a/crypto/x509/v3_asid.c +++ b/crypto/x509/v3_asid.c @@ -545,6 +545,11 @@ static void *v2i_ASIdentifiers(const struct v3_ext_method *method, goto err; } + if (val->value == NULL) { + ERR_raise(ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR); + goto err; + } + /* * Handle inheritance. */ diff --git a/crypto/x509/v3_crld.c b/crypto/x509/v3_crld.c index 08df3faf86eef..e9f6e08e27a7c 100644 --- a/crypto/x509/v3_crld.c +++ b/crypto/x509/v3_crld.c @@ -70,6 +70,11 @@ static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *fnm = NULL; STACK_OF(X509_NAME_ENTRY) *rnm = NULL; + if (cnf->value == NULL) { + ERR_raise(ERR_LIB_X509V3, X509V3_R_MISSING_VALUE); + goto err; + } + if (HAS_PREFIX(cnf->name, "fullname")) { fnm = gnames_from_sectname(ctx, cnf->value); if (!fnm) diff --git a/crypto/x509/v3_ist.c b/crypto/x509/v3_ist.c index 978a0f3ed8670..4d5fe82f329e1 100644 --- a/crypto/x509/v3_ist.c +++ b/crypto/x509/v3_ist.c @@ -50,25 +50,33 @@ static ISSUER_SIGN_TOOL *v2i_issuer_sign_tool(X509V3_EXT_METHOD *method, X509V3_ } if (strcmp(cnf->name, "signTool") == 0) { ist->signTool = ASN1_UTF8STRING_new(); - if (ist->signTool == NULL || !ASN1_STRING_set(ist->signTool, cnf->value, strlen(cnf->value))) { + if (ist->signTool == NULL + || cnf->value == NULL + || !ASN1_STRING_set(ist->signTool, cnf->value, strlen(cnf->value))) { ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB); goto err; } } else if (strcmp(cnf->name, "cATool") == 0) { ist->cATool = ASN1_UTF8STRING_new(); - if (ist->cATool == NULL || !ASN1_STRING_set(ist->cATool, cnf->value, strlen(cnf->value))) { + if (ist->cATool == NULL + || cnf->value == NULL + || !ASN1_STRING_set(ist->cATool, cnf->value, strlen(cnf->value))) { ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB); goto err; } } else if (strcmp(cnf->name, "signToolCert") == 0) { ist->signToolCert = ASN1_UTF8STRING_new(); - if (ist->signToolCert == NULL || !ASN1_STRING_set(ist->signToolCert, cnf->value, strlen(cnf->value))) { + if (ist->signToolCert == NULL + || cnf->value == NULL + || !ASN1_STRING_set(ist->signToolCert, cnf->value, strlen(cnf->value))) { ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB); goto err; } } else if (strcmp(cnf->name, "cAToolCert") == 0) { ist->cAToolCert = ASN1_UTF8STRING_new(); - if (ist->cAToolCert == NULL || !ASN1_STRING_set(ist->cAToolCert, cnf->value, strlen(cnf->value))) { + if (ist->cAToolCert == NULL + || cnf->value == NULL + || !ASN1_STRING_set(ist->cAToolCert, cnf->value, strlen(cnf->value))) { ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB); goto err; } diff --git a/test/invalid-x509.cnf b/test/invalid-x509.cnf new file mode 100644 index 0000000000000..f982edb979750 --- /dev/null +++ b/test/invalid-x509.cnf @@ -0,0 +1,6 @@ +[ext] +issuerSignTool = signTool +sbgp-autonomousSysNum = AS +issuingDistributionPoint = fullname +sbgp-ipAddrBlock = IPv4-SAFI + diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 9bf011c1885cd..9b11169a98269 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 43; +plan tests => 44; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -217,6 +217,14 @@ ok(run(app(["openssl", "x509", "-in", $a_cert, "-CA", $ca_cert, # verify issuer is CA ok (get_issuer($a2_cert) =~ /CN=ca.example.com/); +my $in_csr = srctop_file('test', 'certs', 'x509-check.csr'); +my $in_key = srctop_file('test', 'certs', 'x509-check-key.pem'); +my $invextfile = srctop_file('test', 'invalid-x509.cnf'); +# Test that invalid extensions settings fail +ok(!run(app(["openssl", "x509", "-req", "-in", $in_csr, "-signkey", $in_key, + "-out", "/dev/null", "-days", "3650" , "-extensions", "ext", + "-extfile", $invextfile]))); + # Tests for issue #16080 (fixed in 1.1.1o) my $b_key = "b-key.pem"; my $b_csr = "b-cert.csr"; From 5963aa8c196d7c5a940a979299a07418527932af Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 3 Jan 2024 13:47:05 -0500 Subject: [PATCH 30/81] cleanse stack variable in kdf_pbkdf1_do_derive kdf_pbkdf1_do_derive stores key derivation information in a stack variable, which is left uncleansed prior to returning. Ensure that the stack information is zeroed prior to return to avoid potential leaks of key information Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23194) --- providers/implementations/kdfs/pbkdf1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/implementations/kdfs/pbkdf1.c b/providers/implementations/kdfs/pbkdf1.c index 4fa6afd104a26..33e0ee6009ed0 100644 --- a/providers/implementations/kdfs/pbkdf1.c +++ b/providers/implementations/kdfs/pbkdf1.c @@ -89,6 +89,7 @@ static int kdf_pbkdf1_do_derive(const unsigned char *pass, size_t passlen, memcpy(out, md_tmp, n); ret = 1; err: + OPENSSL_cleanse(md_tmp, EVP_MAX_MD_SIZE); EVP_MD_CTX_free(ctx); return ret; } From 3077bfb78e6fcca006359dc9e3f2b37ad104222d Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 18 Dec 2023 12:49:08 +0100 Subject: [PATCH 31/81] Fix VMS installation - update vmsconfig.pm for consistency An effort was made to update the VMS installation data to align with configuration data. This touched the script templates in VMS/, but didn't update the generation of vmsconfig.pm to match... and also missed a spot. This change adds the missing updates Ref: https://github.com/openssl/openssl/pull/16842 Fixes #22899 Reviewed-by: Tomas Mraz Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/23081) (cherry picked from commit 4058e121cbc6818235b0dcb618e636ce3c4d1f2f) --- Configurations/descrip.mms.tmpl | 8 +++++--- VMS/openssl_ivp.com.in | 4 ++-- VMS/openssl_shutdown.com.in | 8 ++++---- VMS/openssl_startup.com.in | 8 ++++---- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Configurations/descrip.mms.tmpl b/Configurations/descrip.mms.tmpl index e9fb13f24fa57..94eb7e28102e0 100644 --- a/Configurations/descrip.mms.tmpl +++ b/Configurations/descrip.mms.tmpl @@ -749,13 +749,15 @@ vmsconfig.pm : configdata.pm WRITE CONFIG " shlib_version => '","{- $config{shlib_version} -}","'," WRITE CONFIG " shlib_major => '","{- $config{shlib_major} -}","'," WRITE CONFIG " shlib_minor => '","{- $config{shlib_minor} -}","'," - WRITE CONFIG " no_shared => '","{- $disabled{shared} -}","'," WRITE CONFIG " INSTALLTOP => '$(INSTALLTOP)'," WRITE CONFIG " OPENSSLDIR => '$(OPENSSLDIR)'," + WRITE CONFIG ");" + WRITE CONFIG "our %target = (" WRITE CONFIG " pointer_size => '","{- $target{pointer_size} -}","'," WRITE CONFIG ");" - WRITE CONFIG "our %target = ();" - WRITE CONFIG "our %disabled = ();" + WRITE CONFIG "our %disabled = (" + WRITE CONFIG " shared => '","{- $disabled{shared} -}","'," + WRITE CONFIG ");" WRITE CONFIG "our %withargs = ();" WRITE CONFIG "our %unified_info = ();" WRITE CONFIG "1;" diff --git a/VMS/openssl_ivp.com.in b/VMS/openssl_ivp.com.in index 6810792b38d3d..582e1fe1a7fa5 100644 --- a/VMS/openssl_ivp.com.in +++ b/VMS/openssl_ivp.com.in @@ -21,9 +21,9 @@ $ @'INSTALLTOP_'SYS$STARTUP]openssl_startup'v' $ @'INSTALLTOP_'SYS$STARTUP]openssl_utils'v' $ $ IF F$SEARCH("OSSL$LIBCRYPTO''pz'") .EQS. "" - - .OR. F$SEARCH("OSSL$LIBSSL''pz'") .EQS. "" {- output_off() if $config{no_shared}; "" -}- + .OR. F$SEARCH("OSSL$LIBSSL''pz'") .EQS. "" {- output_off() if $disabled{shared}; "" -}- .OR. F$SEARCH("OSSL$LIBCRYPTO_SHR''pz'") .EQS. "" - - .OR. F$SEARCH("OSSL$LIBSSL_SHR''pz'") .EQS. "" {- output_on() if $config{no_shared}; "" -}- + .OR. F$SEARCH("OSSL$LIBSSL_SHR''pz'") .EQS. "" {- output_on() if $disabled{shared}; "" -}- .OR. F$SEARCH("OSSL$INCLUDE:[OPENSSL]crypto.h") .EQS. "" - .OR. F$SEARCH("OPENSSL:crypto.h") .EQS. "" - .OR. F$SEARCH("OSSL$EXE:OPENSSL''v'.EXE") .EQS. "" diff --git a/VMS/openssl_shutdown.com.in b/VMS/openssl_shutdown.com.in index 4193c900f9e99..c2b9cf6c70b41 100644 --- a/VMS/openssl_shutdown.com.in +++ b/VMS/openssl_shutdown.com.in @@ -39,19 +39,19 @@ $ DEAS OSSL$MODULES'pz' $ DEAS OSSL$EXE $ DEAS OSSL$LIBCRYPTO'pz' $ DEAS OSSL$LIBSSL'pz' -${- output_off() if $config{no_shared}; "" -} +${- output_off() if $disabled{shared}; "" -} $ DEAS OSSL$LIBCRYPTO'sv'_SHR'pz' $ DEAS OSSL$LIBSSL'sv'_SHR'pz' -${- output_on() if $config{no_shared}; "" -} +${- output_on() if $disabled{shared}; "" -} $ DEAS OPENSSL $ $ IF P2 .NES. "NOALIASES" $ THEN $ DEAS OSSL$ENGINES'pz' -${- output_off() if $config{no_shared}; "" -} +${- output_off() if $disabled{shared}; "" -} $ DEAS OSSL$LIBCRYPTO_SHR'pz' $ DEAS OSSL$LIBSSL_SHR'pz' -${- output_on() if $config{no_shared}; "" -} +${- output_on() if $disabled{shared}; "" -} $ ENDIF $ $ EXIT 'status' diff --git a/VMS/openssl_startup.com.in b/VMS/openssl_startup.com.in index bbf3e3b4e6e48..738f508d56f53 100644 --- a/VMS/openssl_startup.com.in +++ b/VMS/openssl_startup.com.in @@ -103,19 +103,19 @@ $ DEF OSSL$EXE OSSL$INSTROOT:[EXE.'arch'],- OSSL$INSTROOT:[EXE] $ DEF OSSL$LIBCRYPTO'pz' OSSL$LIB:OSSL$LIBCRYPTO'pz'.OLB $ DEF OSSL$LIBSSL'pz' OSSL$LIB:OSSL$LIBSSL'pz'.OLB -${- output_off() if $config{no_shared}; "" -} +${- output_off() if $disabled{shared}; "" -} $ DEF OSSL$LIBCRYPTO'sv'_SHR'pz' OSSL$SHARE:OSSL$LIBCRYPTO'sv'_SHR'pz'.EXE $ DEF OSSL$LIBSSL'sv'_SHR'pz' OSSL$SHARE:OSSL$LIBSSL'sv'_SHR'pz'.EXE -${- output_on() if $config{no_shared}; "" -} +${- output_on() if $disabled{shared}; "" -} $ DEF OPENSSL OSSL$INCLUDE:[OPENSSL] $ $ IF P2 .NES. "NOALIASES" $ THEN $ DEF OSSL$ENGINES'pz' OSSL$ENGINES'sv''pz' -${- output_off() if $config{no_shared}; "" -} +${- output_off() if $disabled{shared}; "" -} $ DEF OSSL$LIBCRYPTO_SHR'pz' OSSL$LIBCRYPTO'sv'_SHR'pz' $ DEF OSSL$LIBSSL_SHR'pz' OSSL$LIBSSL'sv'_SHR'pz' -${- output_on() if $config{no_shared}; "" -} +${- output_on() if $disabled{shared}; "" -} $ ENDIF $ $ bailout: From 8d8c1600aed80b30e6dc00cbf1a9559feabec8ca Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 20 Dec 2023 08:25:22 +0100 Subject: [PATCH 32/81] VMS: Add the missing -p32 and -p64 variants for x86_64 The pointer size support is already in the code, and is present for all other supported hardwares. Fixes #22899 Reviewed-by: Tomas Mraz Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/23081) (cherry picked from commit a43f253d586279b5d96fffcaf1b26c7a2b0dd938) --- Configurations/10-main.conf | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf index 7fb0fda866669..2a047caa7d4a4 100644 --- a/Configurations/10-main.conf +++ b/Configurations/10-main.conf @@ -2125,5 +2125,15 @@ my %targets = ( inherit_from => [ "vms-generic" ], bn_ops => "SIXTY_FOUR_BIT", pointer_size => "", + }, + "vms-x86_64-p32" => { + inherit_from => [ "vms-x86_64" ], + cflags => add("/POINTER_SIZE=32"), + pointer_size => "32", + }, + "vms-x86_64-p64" => { + inherit_from => [ "vms-x86_64" ], + cflags => add("/POINTER_SIZE=64=ARGV"), + pointer_size => "64", } ); From 7054fc1ca3945342777f588fba43b77f669509ad Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 5 Jan 2024 11:01:34 +0100 Subject: [PATCH 33/81] Avoid memory leak if SXNET_add_id_INTEGER() fails Fixes Coverity 1560046 Reviewed-by: Matt Caswell Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/23211) --- crypto/x509/v3_sxnet.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crypto/x509/v3_sxnet.c b/crypto/x509/v3_sxnet.c index 8540f10d1ecdc..36620a2b67457 100644 --- a/crypto/x509/v3_sxnet.c +++ b/crypto/x509/v3_sxnet.c @@ -123,7 +123,11 @@ int SXNET_add_id_asc(SXNET **psx, const char *zone, const char *user, int userle ERR_raise(ERR_LIB_X509V3, X509V3_R_ERROR_CONVERTING_ZONE); return 0; } - return SXNET_add_id_INTEGER(psx, izone, user, userlen); + if (!SXNET_add_id_INTEGER(psx, izone, user, userlen)) { + ASN1_INTEGER_free(izone); + return 0; + } + return 1; } /* Add an id given the zone as an unsigned long */ @@ -139,8 +143,11 @@ int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, const char *user, ASN1_INTEGER_free(izone); return 0; } - return SXNET_add_id_INTEGER(psx, izone, user, userlen); - + if (!SXNET_add_id_INTEGER(psx, izone, user, userlen)) { + ASN1_INTEGER_free(izone); + return 0; + } + return 1; } /* From 0a22436ea5826d0089db7f1cd97b7c90135ca165 Mon Sep 17 00:00:00 2001 From: Will Sackfield Date: Tue, 28 Nov 2023 19:57:49 -0500 Subject: [PATCH 34/81] Fail the Configure script with no Configurations * Print a message about why the failure is happening. * Send the usage information. Reviewed-by: Richard Levitte Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22855) --- Configure | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Configure b/Configure index cca1ac8d162ee..846a427cff8a1 100755 --- a/Configure +++ b/Configure @@ -385,6 +385,12 @@ if (defined env($local_config_envname)) { } } +# Fail if no configuration is apparent +if (!%table) { + print "Failed to find any os/compiler configurations. Please make sure the Configurations directory is included.\n"; + &usage; +} + # Save away perl command information $config{perl_cmd} = $^X; $config{perl_version} = $Config{version}; From f3be536686654016adc9e22024c06036f949f2b0 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 28 Aug 2023 08:48:34 -0400 Subject: [PATCH 35/81] Augment RSA provider to generate CRT coefficients on EVP_PKEY_fromdata() It would be helpful to be able to generate RSA's dmp1/dmq1/iqmp values when not provided in the param list to EVP_PKEY_fromdata. Augment the provider in ossl_rsa_fromdata to preform this generation iff: a) At least p q n e and e are provided b) the new parameter OSSL_PARAM_RSA_DERIVE_PQ is set to 1 Fixes #21826 Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/21875) --- CHANGES.md | 6 + crypto/rsa/rsa_backend.c | 156 +++++++++++-- crypto/rsa/rsa_gen.c | 329 ++++++++++++++++++++------ crypto/rsa/rsa_lib.c | 34 ++- crypto/rsa/rsa_local.h | 4 + crypto/rsa/rsa_sp800_56b_gen.c | 56 +++-- doc/man7/EVP_PKEY-RSA.pod | 9 + include/crypto/rsa.h | 6 +- test/evp_extra_test.c | 67 ++++++ test/evp_pkey_provided_test.c | 398 +++++++++++++++++++++++++++++++- util/perl/OpenSSL/paramnames.pm | 1 + 11 files changed, 943 insertions(+), 123 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 625eacb6d40dd..57507381e13e5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -80,6 +80,12 @@ OpenSSL 3.2 ### Changes between 3.1 and 3.2 [xx XXX xxxx] + * The EVP_PKEY_fromdata function has been augmented to allow for the derivation + of CRT (Chinese Remainder Theorem) parameters when requested. See the + OSSL_PKEY_PARAM_DERIVE_FROM_PQ param in the EVP_PKEY-RSA documentation. + + *Neil Horman* + * The BLAKE2b hash algorithm supports a configurable output length by setting the "size" parameter. diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c index 7b2efa88620fa..1a9b783a9b9df 100644 --- a/crypto/rsa/rsa_backend.c +++ b/crypto/rsa/rsa_backend.c @@ -64,22 +64,56 @@ static int collect_numbers(STACK_OF(BIGNUM) *numbers, int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private) { const OSSL_PARAM *param_n, *param_e, *param_d = NULL; - BIGNUM *n = NULL, *e = NULL, *d = NULL; + const OSSL_PARAM *param_p, *param_q = NULL; + const OSSL_PARAM *param_derive = NULL; + BIGNUM *p = NULL, *q = NULL, *n = NULL, *e = NULL, *d = NULL; STACK_OF(BIGNUM) *factors = NULL, *exps = NULL, *coeffs = NULL; int is_private = 0; + int derive_from_pq = 0; + BN_CTX *ctx = NULL; if (rsa == NULL) return 0; param_n = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N); param_e = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); - if (include_private) - param_d = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D); - if ((param_n != NULL && !OSSL_PARAM_get_BN(param_n, &n)) - || (param_e != NULL && !OSSL_PARAM_get_BN(param_e, &e)) - || (param_d != NULL && !OSSL_PARAM_get_BN(param_d, &d))) + if ((param_n == NULL || !OSSL_PARAM_get_BN(param_n, &n)) + || (param_e == NULL || !OSSL_PARAM_get_BN(param_e, &e))) { + ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER); goto err; + } + + if (include_private) { + + param_derive = OSSL_PARAM_locate_const(params, + OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ); + if ((param_derive != NULL) + && !OSSL_PARAM_get_int(param_derive, &derive_from_pq)) + goto err; + + param_d = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D); + if (param_d != NULL && !OSSL_PARAM_get_BN(param_d, &d)) { + ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + if (derive_from_pq) { + ctx = BN_CTX_new_ex(rsa->libctx); + if (ctx == NULL) + goto err; + + /* we need at minimum p, q */ + param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR1); + param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR2); + if ((param_p == NULL || !OSSL_PARAM_get_BN(param_p, &p)) + || (param_q == NULL || !OSSL_PARAM_get_BN(param_q, &q))) { + ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + } + } is_private = (d != NULL); @@ -96,25 +130,121 @@ int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private) ossl_rsa_mp_coeff_names)) goto err; - /* It's ok if this private key just has n, e and d */ + if (derive_from_pq && sk_BIGNUM_num(exps) == 0 + && sk_BIGNUM_num(coeffs) == 0) { + /* + * If we want to use crt to derive our exponents/coefficients, we + * need to have at least 2 factors + */ + if (sk_BIGNUM_num(factors) < 2) { + ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + /* + * if we have more than two factors, n and d must also have + * been provided + */ + if (sk_BIGNUM_num(factors) > 2 + && (param_n == NULL || param_d == NULL)) { + ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + /* build our exponents and coefficients here */ + if (sk_BIGNUM_num(factors) == 2) { + /* for 2 factors we can use the sp800 functions to do this */ + if (!RSA_set0_factors(rsa, sk_BIGNUM_value(factors, 0), + sk_BIGNUM_value(factors, 1))) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + /* + * once consumed by RSA_set0_factors, pop those off the stack + * so we don't free them below + */ + sk_BIGNUM_pop(factors); + sk_BIGNUM_pop(factors); + + /* + * Note: Because we only have 2 factors here, there will be no + * additional pinfo fields to hold additional factors, and + * since we set our key and 2 factors above we can skip + * the call to ossl_rsa_set0_all_params + */ + if (!ossl_rsa_sp800_56b_derive_params_from_pq(rsa, + RSA_bits(rsa), + NULL, ctx)) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } else { +#ifndef FIPS_MODULE + /* + * in the multiprime case we have to generate exps/coeffs here + * for each additional prime + */ + if (!ossl_rsa_multiprime_derive(rsa, RSA_bits(rsa), + sk_BIGNUM_num(factors), + rsa->e, factors, exps, + coeffs)) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* + * Now we should have all our factors, exponents and + * coefficients + */ + if (!ossl_rsa_set0_all_params(rsa, factors, exps, coeffs)) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + +#else + /* multiprime case is disallowed in FIPS mode, raise an error */ + ERR_raise(ERR_LIB_RSA, ERR_R_UNSUPPORTED); + goto err; +#endif + } + + } else { + /* + * It's ok if this private key just has n, e and d + * but only if we're not using derive_from_pq + */ + if (sk_BIGNUM_num(factors) != 0 + && !ossl_rsa_set0_all_params(rsa, factors, exps, coeffs)) + goto err; + } + /* sanity check to ensure we used everything in our stacks */ if (sk_BIGNUM_num(factors) != 0 - && !ossl_rsa_set0_all_params(rsa, factors, exps, coeffs)) + || sk_BIGNUM_num(exps) != 0 + || sk_BIGNUM_num(coeffs) != 0) { + ERR_raise_data(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR, + "There are %d, %d, %d elements left on our factors, exps, coeffs stacks\n", + sk_BIGNUM_num(factors), sk_BIGNUM_num(exps), + sk_BIGNUM_num(coeffs)); goto err; + } } - + BN_clear_free(p); + BN_clear_free(q); sk_BIGNUM_free(factors); sk_BIGNUM_free(exps); sk_BIGNUM_free(coeffs); + BN_CTX_free(ctx); return 1; err: BN_free(n); BN_free(e); BN_free(d); - sk_BIGNUM_pop_free(factors, BN_free); - sk_BIGNUM_pop_free(exps, BN_free); - sk_BIGNUM_pop_free(coeffs, BN_free); + sk_BIGNUM_pop_free(factors, BN_clear_free); + sk_BIGNUM_pop_free(exps, BN_clear_free); + sk_BIGNUM_pop_free(coeffs, BN_clear_free); + BN_CTX_free(ctx); return 0; } @@ -152,7 +282,7 @@ int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[], || !ossl_param_build_set_multi_key_bn(bld, params, ossl_rsa_mp_coeff_names, coeffs)) - goto err; + goto err; } #if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS) diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 0cdbb3fde2501..f67e1152bbdaa 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -71,15 +71,201 @@ int RSA_generate_multi_prime_key(RSA *rsa, int bits, int primes, return rsa_keygen(rsa->libctx, rsa, bits, primes, e_value, cb, 0); } +DEFINE_STACK_OF(BIGNUM) + +/* + * Given input values, q, p, n, d and e, derive the exponents + * and coefficients for each prime in this key, placing the result + * on their respective exps and coeffs stacks + */ #ifndef FIPS_MODULE +int ossl_rsa_multiprime_derive(RSA *rsa, int bits, int primes, + BIGNUM *e_value, + STACK_OF(BIGNUM) *factors, + STACK_OF(BIGNUM) *exps, + STACK_OF(BIGNUM) *coeffs) +{ + STACK_OF(BIGNUM) *pplist = NULL, *pdlist = NULL; + BIGNUM *factor = NULL, *newpp = NULL, *newpd = NULL; + BIGNUM *dval = NULL, *newexp = NULL, *newcoeff = NULL; + BIGNUM *p = NULL, *q = NULL; + BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; + BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL; + BN_CTX *ctx = NULL; + BIGNUM *tmp = NULL; + int i; + int ret = 0; + + ctx = BN_CTX_new_ex(rsa->libctx); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + + pplist = sk_BIGNUM_new_null(); + if (pplist == NULL) + goto err; + + pdlist = sk_BIGNUM_new_null(); + if (pdlist == NULL) + goto err; + + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + + if (r2 == NULL) + goto err; + + BN_set_flags(r0, BN_FLG_CONSTTIME); + BN_set_flags(r1, BN_FLG_CONSTTIME); + BN_set_flags(r2, BN_FLG_CONSTTIME); + + if (BN_copy(r1, rsa->n) == NULL) + goto err; + + p = sk_BIGNUM_value(factors, 0); + q = sk_BIGNUM_value(factors, 1); + + /* Build list of partial products of primes */ + for (i = 0; i < sk_BIGNUM_num(factors); i++) { + switch (i) { + case 0: + /* our first prime, p */ + if (!BN_sub(r2, p, BN_value_one())) + goto err; + BN_set_flags(r2, BN_FLG_CONSTTIME); + if (BN_mod_inverse(r1, r2, rsa->e, ctx) == NULL) + goto err; + break; + case 1: + /* second prime q */ + if (!BN_mul(r1, p, q, ctx)) + goto err; + tmp = BN_dup(r1); + if (tmp == NULL) + goto err; + if (!sk_BIGNUM_insert(pplist, tmp, sk_BIGNUM_num(pplist))) + goto err; + break; + default: + factor = sk_BIGNUM_value(factors, i); + /* all other primes */ + if (!BN_mul(r1, r1, factor, ctx)) + goto err; + tmp = BN_dup(r1); + if (tmp == NULL) + goto err; + if (!sk_BIGNUM_insert(pplist, tmp, sk_BIGNUM_num(pplist))) + goto err; + break; + } + } + + /* build list of relative d values */ + /* p -1 */ + if (!BN_sub(r1, p, BN_value_one())) + goto err; + if (!BN_sub(r2, q, BN_value_one())) + goto err; + if (!BN_mul(r0, r1, r2, ctx)) + goto err; + for (i = 2; i < sk_BIGNUM_num(factors); i++) { + factor = sk_BIGNUM_value(factors, i); + dval = BN_new(); + if (dval == NULL) + goto err; + BN_set_flags(dval, BN_FLG_CONSTTIME); + if (!BN_sub(dval, factor, BN_value_one())) + goto err; + if (!BN_mul(r0, r0, dval, ctx)) + goto err; + if (!sk_BIGNUM_insert(pdlist, dval, sk_BIGNUM_num(pdlist))) + goto err; + } + + /* Calculate dmp1, dmq1 and additional exponents */ + dmp1 = BN_secure_new(); + if (dmp1 == NULL) + goto err; + dmq1 = BN_secure_new(); + if (dmq1 == NULL) + goto err; + + if (!BN_mod(dmp1, rsa->d, r1, ctx)) + goto err; + if (!sk_BIGNUM_insert(exps, dmp1, sk_BIGNUM_num(exps))) + goto err; + dmp1 = NULL; + + if (!BN_mod(dmq1, rsa->d, r2, ctx)) + goto err; + if (!sk_BIGNUM_insert(exps, dmq1, sk_BIGNUM_num(exps))) + goto err; + dmq1 = NULL; + + for (i = 2; i < sk_BIGNUM_num(factors); i++) { + newpd = sk_BIGNUM_value(pdlist, i - 2); + newexp = BN_new(); + if (newexp == NULL) + goto err; + if (!BN_mod(newexp, rsa->d, newpd, ctx)) { + BN_free(newexp); + goto err; + } + if (!sk_BIGNUM_insert(exps, newexp, sk_BIGNUM_num(exps))) + goto err; + } + + /* Calculate iqmp and additional coefficients */ + iqmp = BN_new(); + if (iqmp == NULL) + goto err; + + if (BN_mod_inverse(iqmp, sk_BIGNUM_value(factors, 1), + sk_BIGNUM_value(factors, 0), ctx) == NULL) + goto err; + if (!sk_BIGNUM_insert(coeffs, iqmp, sk_BIGNUM_num(coeffs))) + goto err; + iqmp = NULL; + + for (i = 2; i < sk_BIGNUM_num(factors); i++) { + newpp = sk_BIGNUM_value(pplist, i - 2); + newcoeff = BN_new(); + if (newcoeff == NULL) + goto err; + if (BN_mod_inverse(newcoeff, newpp, sk_BIGNUM_value(factors, i), + ctx) == NULL) { + BN_free(newcoeff); + goto err; + } + if (!sk_BIGNUM_insert(coeffs, newcoeff, sk_BIGNUM_num(coeffs))) + goto err; + } + + ret = 1; + err: + sk_BIGNUM_pop_free(pplist, BN_free); + sk_BIGNUM_pop_free(pdlist, BN_free); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + BN_clear_free(dmp1); + BN_clear_free(dmq1); + BN_clear_free(iqmp); + return ret; +} + static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value, BN_GENCB *cb) { - BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *tmp, *prime; + BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *tmp, *tmp2, *prime; int n = 0, bitsr[RSA_MAX_PRIME_NUM], bitse = 0; int i = 0, quo = 0, rmd = 0, adj = 0, retries = 0; RSA_PRIME_INFO *pinfo = NULL; STACK_OF(RSA_PRIME_INFO) *prime_infos = NULL; + STACK_OF(BIGNUM) *factors = NULL; + STACK_OF(BIGNUM) *exps = NULL; + STACK_OF(BIGNUM) *coeffs = NULL; BN_CTX *ctx = NULL; BN_ULONG bitst = 0; unsigned long error = 0; @@ -104,6 +290,18 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, return 0; } + factors = sk_BIGNUM_new_null(); + if (factors == NULL) + return 0; + + exps = sk_BIGNUM_new_null(); + if (exps == NULL) + goto err; + + coeffs = sk_BIGNUM_new_null(); + if (coeffs == NULL) + goto err; + ctx = BN_CTX_new_ex(rsa->libctx); if (ctx == NULL) goto err; @@ -137,15 +335,6 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, if (!rsa->q && ((rsa->q = BN_secure_new()) == NULL)) goto err; BN_set_flags(rsa->q, BN_FLG_CONSTTIME); - if (!rsa->dmp1 && ((rsa->dmp1 = BN_secure_new()) == NULL)) - goto err; - BN_set_flags(rsa->dmp1, BN_FLG_CONSTTIME); - if (!rsa->dmq1 && ((rsa->dmq1 = BN_secure_new()) == NULL)) - goto err; - BN_set_flags(rsa->dmq1, BN_FLG_CONSTTIME); - if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL)) - goto err; - BN_set_flags(rsa->iqmp, BN_FLG_CONSTTIME); /* initialize multi-prime components */ if (primes > RSA_DEFAULT_PRIME_NUM) { @@ -220,7 +409,7 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, ERR_set_mark(); BN_set_flags(r2, BN_FLG_CONSTTIME); if (BN_mod_inverse(r1, r2, rsa->e, ctx) != NULL) { - /* GCD == 1 since inverse exists */ + /* GCD == 1 since inverse exists */ break; } error = ERR_peek_last_error(); @@ -250,8 +439,14 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, /* i == 0, do nothing */ if (!BN_GENCB_call(cb, 3, i)) goto err; + tmp = BN_dup(prime); + if (tmp == NULL) + goto err; + if (!sk_BIGNUM_insert(factors, tmp, sk_BIGNUM_num(factors))) + goto err; continue; } + /* * if |r1|, product of factors so far, is not as long as expected * (by checking the first 4 bits are less than 0x9 or greater than @@ -298,6 +493,10 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, */ i = -1; bitse = 0; + sk_BIGNUM_pop_free(factors, BN_clear_free); + factors = sk_BIGNUM_new_null(); + if (factors == NULL) + goto err; continue; } retries++; @@ -310,12 +509,20 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, goto err; if (!BN_GENCB_call(cb, 3, i)) goto err; + tmp = BN_dup(prime); + if (tmp == NULL) + goto err; + if (!sk_BIGNUM_insert(factors, tmp, sk_BIGNUM_num(factors))) + goto err; } if (BN_cmp(rsa->p, rsa->q) < 0) { tmp = rsa->p; rsa->p = rsa->q; rsa->q = tmp; + /* mirror this in our factor stack */ + if (!sk_BIGNUM_insert(factors, sk_BIGNUM_delete(factors, 0), 1)) + goto err; } /* calculate d */ @@ -339,79 +546,51 @@ static int rsa_multiprime_keygen(RSA *rsa, int bits, int primes, goto err; } - { - BIGNUM *pr0 = BN_new(); - if (pr0 == NULL) - goto err; - - BN_with_flags(pr0, r0, BN_FLG_CONSTTIME); - if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) { - BN_free(pr0); - goto err; /* d */ - } - /* We MUST free pr0 before any further use of r0 */ - BN_free(pr0); - } - - { - BIGNUM *d = BN_new(); - - if (d == NULL) - goto err; - - BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - - /* calculate d mod (p-1) and d mod (q - 1) */ - if (!BN_mod(rsa->dmp1, d, r1, ctx) - || !BN_mod(rsa->dmq1, d, r2, ctx)) { - BN_free(d); - goto err; - } - - /* calculate CRT exponents */ - for (i = 2; i < primes; i++) { - pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2); - /* pinfo->d == r_i - 1 */ - if (!BN_mod(pinfo->d, d, pinfo->d, ctx)) { - BN_free(d); - goto err; - } - } - - /* We MUST free d before any further use of rsa->d */ - BN_free(d); + BN_set_flags(r0, BN_FLG_CONSTTIME); + if (BN_mod_inverse(rsa->d, rsa->e, r0, ctx) == NULL) { + goto err; /* d */ } - { - BIGNUM *p = BN_new(); + /* derive any missing exponents and coefficients */ + if (!ossl_rsa_multiprime_derive(rsa, bits, primes, e_value, + factors, exps, coeffs)) + goto err; - if (p == NULL) + /* + * first 2 factors/exps are already tracked in p/q/dmq1/dmp1 + * and the first coeff is in iqmp, so pop those off the stack + * Note, the first 2 factors/exponents are already tracked by p and q + * assign dmp1/dmq1 and iqmp + * the remaining pinfo values are separately allocated, so copy and delete + * those + */ + BN_clear_free(sk_BIGNUM_delete(factors, 0)); + BN_clear_free(sk_BIGNUM_delete(factors, 0)); + rsa->dmp1 = sk_BIGNUM_delete(exps, 0); + rsa->dmq1 = sk_BIGNUM_delete(exps, 0); + rsa->iqmp = sk_BIGNUM_delete(coeffs, 0); + for (i = 2; i < primes; i++) { + pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2); + tmp = sk_BIGNUM_delete(factors, 0); + BN_copy(pinfo->r, tmp); + BN_clear_free(tmp); + tmp = sk_BIGNUM_delete(exps, 0); + tmp2 = BN_copy(pinfo->d, tmp); + BN_clear_free(tmp); + if (tmp2 == NULL) goto err; - BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); - - /* calculate inverse of q mod p */ - if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) { - BN_free(p); + tmp = sk_BIGNUM_delete(coeffs, 0); + tmp2 = BN_copy(pinfo->t, tmp); + BN_clear_free(tmp); + if (tmp2 == NULL) goto err; - } - - /* calculate CRT coefficient for other primes */ - for (i = 2; i < primes; i++) { - pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2); - BN_with_flags(p, pinfo->r, BN_FLG_CONSTTIME); - if (!BN_mod_inverse(pinfo->t, pinfo->pp, p, ctx)) { - BN_free(p); - goto err; - } - } - - /* We MUST free p before any further use of rsa->p */ - BN_free(p); } - ok = 1; err: + sk_BIGNUM_free(factors); + sk_BIGNUM_free(exps); + sk_BIGNUM_free(coeffs); if (ok == -1) { ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); ok = 0; diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index 1c3b33c28b332..1bd1a0a7bd163 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -744,9 +744,13 @@ int RSA_pkey_ctx_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2) DEFINE_STACK_OF(BIGNUM) -int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, - const STACK_OF(BIGNUM) *exps, - const STACK_OF(BIGNUM) *coeffs) +/* + * Note: This function deletes values from the parameter + * stack values as they are consumed and set in the RSA key. + */ +int ossl_rsa_set0_all_params(RSA *r, STACK_OF(BIGNUM) *primes, + STACK_OF(BIGNUM) *exps, + STACK_OF(BIGNUM) *coeffs) { #ifndef FIPS_MODULE STACK_OF(RSA_PRIME_INFO) *prime_infos, *old_infos = NULL; @@ -757,6 +761,8 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, return 0; pnum = sk_BIGNUM_num(primes); + + /* we need at least 2 primes */ if (pnum < 2) return 0; @@ -764,6 +770,17 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, sk_BIGNUM_value(primes, 1))) return 0; + /* + * if we managed to set everything above, remove those elements from the + * stack + * Note, we do this after the above all to ensure that we have taken + * ownership of all the elements in the RSA key to avoid memory leaks + * we also use delete 0 here as we are grabbing items from the end of the + * stack rather than the start, otherwise we could use pop + */ + sk_BIGNUM_delete(primes, 0); + sk_BIGNUM_delete(primes, 0); + if (pnum == sk_BIGNUM_num(exps) && pnum == sk_BIGNUM_num(coeffs) + 1) { @@ -771,6 +788,11 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, sk_BIGNUM_value(exps, 1), sk_BIGNUM_value(coeffs, 0))) return 0; + + /* as above, once we consume the above params, delete them from the list */ + sk_BIGNUM_delete(exps, 0); + sk_BIGNUM_delete(exps, 0); + sk_BIGNUM_delete(coeffs, 0); } #ifndef FIPS_MODULE @@ -786,9 +808,9 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, return 0; for (i = 2; i < pnum; i++) { - BIGNUM *prime = sk_BIGNUM_value(primes, i); - BIGNUM *exp = sk_BIGNUM_value(exps, i); - BIGNUM *coeff = sk_BIGNUM_value(coeffs, i - 1); + BIGNUM *prime = sk_BIGNUM_pop(primes); + BIGNUM *exp = sk_BIGNUM_pop(exps); + BIGNUM *coeff = sk_BIGNUM_pop(coeffs); RSA_PRIME_INFO *pinfo = NULL; if (!ossl_assert(prime != NULL && exp != NULL && coeff != NULL)) diff --git a/crypto/rsa/rsa_local.h b/crypto/rsa/rsa_local.h index ea70da05ad780..f0084aeab4853 100644 --- a/crypto/rsa/rsa_local.h +++ b/crypto/rsa/rsa_local.h @@ -150,6 +150,10 @@ struct rsa_meth_st { /* Macros to test if a pkey or ctx is for a PSS key */ #define pkey_is_pss(pkey) (pkey->ameth->pkey_id == EVP_PKEY_RSA_PSS) #define pkey_ctx_is_pss(ctx) (ctx->pmeth->pkey_id == EVP_PKEY_RSA_PSS) +int ossl_rsa_multiprime_derive(RSA *rsa, int bits, int primes, + BIGNUM *e_value, + STACK_OF(BIGNUM) *factors, STACK_OF(BIGNUM) *exps, + STACK_OF(BIGNUM) *coeffs); RSA_PSS_PARAMS *ossl_rsa_pss_params_create(const EVP_MD *sigmd, const EVP_MD *mgf1md, int saltlen); diff --git a/crypto/rsa/rsa_sp800_56b_gen.c b/crypto/rsa/rsa_sp800_56b_gen.c index 9fa85bfdf3b69..bcc0fceab0aa3 100644 --- a/crypto/rsa/rsa_sp800_56b_gen.c +++ b/crypto/rsa/rsa_sp800_56b_gen.c @@ -228,13 +228,16 @@ static int rsa_validate_rng_strength(EVP_RAND_CTX *rng, int nbits) * Returns: -1 = error, * 0 = d is too small, * 1 = success. + * + * SP800-56b key generation always passes a non NULL value for e. + * For other purposes, if e is NULL then it is assumed that e, n and d are + * already set in the RSA key and do not need to be recalculated. */ int ossl_rsa_sp800_56b_derive_params_from_pq(RSA *rsa, int nbits, const BIGNUM *e, BN_CTX *ctx) { int ret = -1; BIGNUM *p1, *q1, *lcm, *p1q1, *gcd; - BN_CTX_start(ctx); p1 = BN_CTX_get(ctx); q1 = BN_CTX_get(ctx); @@ -254,32 +257,37 @@ int ossl_rsa_sp800_56b_derive_params_from_pq(RSA *rsa, int nbits, if (ossl_rsa_get_lcm(ctx, rsa->p, rsa->q, lcm, gcd, p1, q1, p1q1) != 1) goto err; - /* copy e */ - BN_free(rsa->e); - rsa->e = BN_dup(e); - if (rsa->e == NULL) - goto err; + /* + * if e is provided as a parameter, don't recompute e, d or n + */ + if (e != NULL) { + /* copy e */ + BN_free(rsa->e); + rsa->e = BN_dup(e); + if (rsa->e == NULL) + goto err; - BN_clear_free(rsa->d); - /* (Step 3) d = (e^-1) mod (LCM(p-1, q-1)) */ - rsa->d = BN_secure_new(); - if (rsa->d == NULL) - goto err; - BN_set_flags(rsa->d, BN_FLG_CONSTTIME); - if (BN_mod_inverse(rsa->d, e, lcm, ctx) == NULL) - goto err; + BN_clear_free(rsa->d); + /* (Step 3) d = (e^-1) mod (LCM(p-1, q-1)) */ + rsa->d = BN_secure_new(); + if (rsa->d == NULL) + goto err; + BN_set_flags(rsa->d, BN_FLG_CONSTTIME); + if (BN_mod_inverse(rsa->d, e, lcm, ctx) == NULL) + goto err; - /* (Step 3) return an error if d is too small */ - if (BN_num_bits(rsa->d) <= (nbits >> 1)) { - ret = 0; - goto err; - } + /* (Step 3) return an error if d is too small */ + if (BN_num_bits(rsa->d) <= (nbits >> 1)) { + ret = 0; + goto err; + } - /* (Step 4) n = pq */ - if (rsa->n == NULL) - rsa->n = BN_new(); - if (rsa->n == NULL || !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) - goto err; + /* (Step 4) n = pq */ + if (rsa->n == NULL) + rsa->n = BN_new(); + if (rsa->n == NULL || !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) + goto err; + } /* (Step 5a) dP = d mod (p-1) */ if (rsa->dmp1 == NULL) diff --git a/doc/man7/EVP_PKEY-RSA.pod b/doc/man7/EVP_PKEY-RSA.pod index dcd38fcee85bb..96562b6be038b 100644 --- a/doc/man7/EVP_PKEY-RSA.pod +++ b/doc/man7/EVP_PKEY-RSA.pod @@ -132,6 +132,15 @@ The RSA "e" value. The value may be any odd number greater than or equal to 65537. The default value is 65537. For legacy reasons a value of 3 is currently accepted but is deprecated. +=item "rsa-derive-from-pq" (B) + +Indicate that missing parameters not passed in the parameter list should be +derived if not provided. Setting a nonzero value will cause all +needed exponents and coefficients to be derived if not available. Setting this +option requires at least OSSL_PARAM_RSA_FACTOR1, OSSL_PARAM_RSA_FACTOR2, +and OSSL_PARAM_RSA_N to be provided. This option is ignored if +OSSL_KEYMGMT_SELECT_PRIVATE_KEY is not set in the selection parameter. + =back =head2 RSA key generation parameters for FIPS module testing diff --git a/include/crypto/rsa.h b/include/crypto/rsa.h index 8eddc168f6d68..cb7f84b301f13 100644 --- a/include/crypto/rsa.h +++ b/include/crypto/rsa.h @@ -54,9 +54,9 @@ RSA *ossl_rsa_new_with_ctx(OSSL_LIB_CTX *libctx); OSSL_LIB_CTX *ossl_rsa_get0_libctx(RSA *r); void ossl_rsa_set0_libctx(RSA *r, OSSL_LIB_CTX *libctx); -int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, - const STACK_OF(BIGNUM) *exps, - const STACK_OF(BIGNUM) *coeffs); +int ossl_rsa_set0_all_params(RSA *r, STACK_OF(BIGNUM) *primes, + STACK_OF(BIGNUM) *exps, + STACK_OF(BIGNUM) *coeffs); int ossl_rsa_get0_all_params(RSA *r, STACK_OF(BIGNUM_const) *primes, STACK_OF(BIGNUM_const) *exps, STACK_OF(BIGNUM_const) *coeffs); diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index f3680a0fb4d95..131879b8e227d 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -3080,6 +3080,70 @@ static int test_RSA_OAEP_set_null_label(void) return ret; } +#ifndef OPENSSL_NO_DEPRECATED_3_0 +static int test_RSA_legacy(void) +{ + int ret = 0; + BIGNUM *p = NULL; + BIGNUM *q = NULL; + BIGNUM *n = NULL; + BIGNUM *e = NULL; + BIGNUM *d = NULL; + const EVP_MD *md = EVP_sha256(); + EVP_MD_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + if (nullprov != NULL) + return TEST_skip("Test does not support a non-default library context"); + + if (!TEST_ptr(p = BN_dup(BN_value_one())) + || !TEST_ptr(q = BN_dup(BN_value_one())) + || !TEST_ptr(n = BN_dup(BN_value_one())) + || !TEST_ptr(e = BN_dup(BN_value_one())) + || !TEST_ptr(d = BN_dup(BN_value_one()))) + goto err; + + if (!TEST_ptr(rsa = RSA_new()) + || !TEST_ptr(pkey = EVP_PKEY_new()) + || !TEST_ptr(ctx = EVP_MD_CTX_new())) + goto err; + + if (!TEST_true(RSA_set0_factors(rsa, p, q))) + goto err; + p = NULL; + q = NULL; + + if (!TEST_true(RSA_set0_key(rsa, n, e, d))) + goto err; + n = NULL; + e = NULL; + d = NULL; + + if (!TEST_true(EVP_PKEY_assign_RSA(pkey, rsa))) + goto err; + + rsa = NULL; + + if (!TEST_true(EVP_DigestSignInit(ctx, NULL, md, NULL, pkey))) + goto err; + + ret = 1; + +err: + RSA_free(rsa); + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + BN_free(p); + BN_free(q); + BN_free(n); + BN_free(e); + BN_free(d); + + return ret; +} +#endif + #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) static int test_decrypt_null_chunks(void) { @@ -5520,6 +5584,9 @@ int setup_tests(void) ADD_TEST(test_RSA_get_set_params); ADD_TEST(test_RSA_OAEP_set_get_params); ADD_TEST(test_RSA_OAEP_set_null_label); +#ifndef OPENSSL_NO_DEPRECATED_3_0 + ADD_TEST(test_RSA_legacy); +#endif #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) ADD_TEST(test_decrypt_null_chunks); #endif diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c index 02e7aa727c6ab..afebd04feb9f7 100644 --- a/test/evp_pkey_provided_test.c +++ b/test/evp_pkey_provided_test.c @@ -429,7 +429,8 @@ static int test_fromdata_rsa(void) /* for better diagnostics always compare key params */ for (i = 0; fromdata_params[i].key != NULL; ++i) { if (!TEST_true(BN_set_word(bn_from, key_numbers[i])) - || !TEST_true(EVP_PKEY_get_bn_param(pk, fromdata_params[i].key, &bn)) + || !TEST_true(EVP_PKEY_get_bn_param(pk, fromdata_params[i].key, + &bn)) || !TEST_BN_eq(bn, bn_from)) ret = 0; } @@ -443,6 +444,397 @@ static int test_fromdata_rsa(void) return ret; } +struct check_data { + const char *pname; + BIGNUM *comparebn; +}; + +static int do_fromdata_rsa_derive(OSSL_PARAM *fromdata_params, + struct check_data check[], + int expected_nbits, int expected_sbits, + int expected_ksize) +{ + const OSSL_PARAM *check_param = NULL; + BIGNUM *check_bn = NULL; + OSSL_PARAM *todata_params = NULL; + EVP_PKEY_CTX *ctx = NULL, *key_ctx = NULL; + EVP_PKEY *pk = NULL, *copy_pk = NULL, *dup_pk = NULL; + int i; + int ret = 0; + + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) + || !TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1) + || !TEST_int_eq(EVP_PKEY_fromdata(ctx, &pk, EVP_PKEY_KEYPAIR, + fromdata_params), 1)) + goto err; + + /* + * get the generated key parameters back and validate that the + * exponents/coeffs are correct + */ + if (!TEST_int_eq(EVP_PKEY_todata(pk, EVP_PKEY_KEYPAIR, &todata_params), 1)) + goto err; + + for (i = 0; check[i].pname != NULL; i++) { + if (!TEST_ptr(check_param = OSSL_PARAM_locate_const(todata_params, + check[i].pname))) + goto err; + if (!TEST_int_eq(OSSL_PARAM_get_BN(check_param, &check_bn), 1)) + goto err; + if (!TEST_BN_eq(check_bn, check[i].comparebn)) { + TEST_info("Data mismatch for parameter %s", check[i].pname); + goto err; + } + BN_free(check_bn); + check_bn = NULL; + } + + while (dup_pk == NULL) { + if (!TEST_int_eq(EVP_PKEY_get_bits(pk), expected_nbits) + || !TEST_int_eq(EVP_PKEY_get_security_bits(pk), expected_sbits) + || !TEST_int_eq(EVP_PKEY_get_size(pk), expected_ksize) + || !TEST_false(EVP_PKEY_missing_parameters(pk))) + goto err; + + EVP_PKEY_CTX_free(key_ctx); + if (!TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, ""))) + goto err; + + if (!TEST_int_gt(EVP_PKEY_check(key_ctx), 0) + || !TEST_int_gt(EVP_PKEY_public_check(key_ctx), 0) + || !TEST_int_gt(EVP_PKEY_private_check(key_ctx), 0) + || !TEST_int_gt(EVP_PKEY_pairwise_check(key_ctx), 0)) + goto err; + + /* EVP_PKEY_copy_parameters() should fail for RSA */ + if (!TEST_ptr(copy_pk = EVP_PKEY_new()) + || !TEST_false(EVP_PKEY_copy_parameters(copy_pk, pk))) + goto err; + EVP_PKEY_free(copy_pk); + copy_pk = NULL; + + if (!TEST_ptr(dup_pk = EVP_PKEY_dup(pk))) + goto err; + if (!TEST_int_eq(EVP_PKEY_eq(pk, dup_pk), 1)) { + EVP_PKEY_free(dup_pk); + goto err; + } + EVP_PKEY_free(pk); + pk = dup_pk; + } + ret = 1; +err: + BN_free(check_bn); + EVP_PKEY_free(pk); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_CTX_free(key_ctx); + OSSL_PARAM_free(fromdata_params); + OSSL_PARAM_free(todata_params); + return ret; +} + +static int test_fromdata_rsa_derive_from_pq_sp800(void) +{ + OSSL_PARAM_BLD *bld = NULL; + BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; + BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; + OSSL_PARAM *fromdata_params = NULL; + struct check_data cdata[4]; + int ret = 0; + /* + * 512-bit RSA key, extracted from this command, + * openssl genrsa 512 | openssl rsa -text + * Note: When generating a key with EVP_PKEY_fromdata, and using + * crt derivation, openssl requires a minimum of 512 bits of n data, + * and 2048 bits in the FIPS case + */ + static unsigned char n_data[] = + {0x00, 0xc7, 0x06, 0xd8, 0x6b, 0x3c, 0x4f, 0xb7, 0x95, 0x42, 0x44, 0x90, + 0xbd, 0xef, 0xf3, 0xc4, 0xb5, 0xa8, 0x55, 0x9e, 0x33, 0xa3, 0x04, 0x3a, + 0x90, 0xe5, 0x13, 0xff, 0x87, 0x69, 0x15, 0xa4, 0x8a, 0x17, 0x10, 0xcc, + 0xdf, 0xf9, 0xc5, 0x0f, 0xf1, 0x12, 0xff, 0x12, 0x11, 0xe5, 0x6b, 0x5c, + 0x83, 0xd9, 0x43, 0xd1, 0x8a, 0x7e, 0xa6, 0x60, 0x07, 0x2e, 0xbb, 0x03, + 0x17, 0x2d, 0xec, 0x17, 0x87}; + static unsigned char e_data[] = {0x01, 0x00, 0x01}; + static unsigned char d_data[] = + {0x1e, 0x5e, 0x5d, 0x07, 0x7f, 0xdc, 0x6a, 0x16, 0xcc, 0x55, 0xca, 0x00, + 0x31, 0x6c, 0xf0, 0xc7, 0x07, 0x38, 0x89, 0x3b, 0x37, 0xd4, 0x9d, 0x5b, + 0x1e, 0x99, 0x3e, 0x94, 0x5a, 0xe4, 0x82, 0x86, 0x8a, 0x78, 0x34, 0x09, + 0x37, 0xd5, 0xe7, 0xb4, 0xef, 0x5f, 0x83, 0x94, 0xff, 0xe5, 0x36, 0x79, + 0x10, 0x0c, 0x38, 0xc5, 0x3a, 0x33, 0xa6, 0x7c, 0x3c, 0xcc, 0x98, 0xe0, + 0xf5, 0xdb, 0xe6, 0x81}; + static unsigned char p_data[] = + {0x00, 0xf6, 0x61, 0x38, 0x0e, 0x1f, 0x82, 0x7c, 0xb8, 0xba, 0x00, 0xd3, + 0xac, 0xdc, 0x4e, 0x6b, 0x7e, 0xf7, 0x58, 0xf3, 0xd9, 0xd8, 0x21, 0xed, + 0x54, 0xa3, 0x36, 0xd2, 0x2c, 0x5f, 0x06, 0x7d, 0xc5}; + static unsigned char q_data[] = + {0x00, 0xce, 0xcc, 0x4a, 0xa5, 0x4f, 0xd6, 0x73, 0xd0, 0x20, 0xc3, 0x98, + 0x64, 0x20, 0x9b, 0xc1, 0x23, 0xd8, 0x5c, 0x82, 0x4f, 0xe8, 0xa5, 0x32, + 0xcd, 0x7e, 0x97, 0xb4, 0xde, 0xf6, 0x4c, 0x80, 0xdb}; + static unsigned char dmp1_data[] = + {0x00, 0xd1, 0x07, 0xb6, 0x79, 0x34, 0xfe, 0x8e, 0x36, 0x63, 0x88, 0xa4, + 0x0e, 0x3a, 0x73, 0x45, 0xfc, 0x58, 0x7a, 0x5d, 0x98, 0xeb, 0x28, 0x0d, + 0xa5, 0x0b, 0x3c, 0x4d, 0xa0, 0x5b, 0x96, 0xb4, 0x49}; + static unsigned char dmq1_data[] = + {0x5b, 0x47, 0x02, 0xdf, 0xaa, 0xb8, 0xae, 0x8f, 0xbc, 0x16, 0x79, 0x6a, + 0x20, 0x96, 0x7f, 0x0e, 0x92, 0x4e, 0x6a, 0xda, 0x58, 0x86, 0xaa, 0x40, + 0xd7, 0xd2, 0xa0, 0x6c, 0x15, 0x6c, 0xb9, 0x27}; + static unsigned char iqmp_data[] = + {0x00, 0xa0, 0xd6, 0xf0, 0xe8, 0x17, 0x9e, 0xe7, 0xe6, 0x99, 0x12, 0xd6, + 0xd9, 0x43, 0xcf, 0xed, 0x37, 0x29, 0xf5, 0x6c, 0x3e, 0xc1, 0x7f, 0x2e, + 0x31, 0x3f, 0x64, 0x34, 0x66, 0x68, 0x5c, 0x22, 0x08}; + + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()) + || !TEST_ptr(n = BN_bin2bn(n_data, sizeof(n_data), NULL)) + || !TEST_ptr(e = BN_bin2bn(e_data, sizeof(e_data), NULL)) + || !TEST_ptr(d = BN_bin2bn(d_data, sizeof(d_data), NULL)) + || !TEST_ptr(p = BN_bin2bn(p_data, sizeof(p_data), NULL)) + || !TEST_ptr(q = BN_bin2bn(q_data, sizeof(q_data), NULL)) + || !TEST_ptr(dmp1 = BN_bin2bn(dmp1_data, sizeof(dmp1_data), NULL)) + || !TEST_ptr(dmq1 = BN_bin2bn(dmq1_data, sizeof(dmq1_data), NULL)) + || !TEST_ptr(iqmp = BN_bin2bn(iqmp_data, sizeof(iqmp_data), NULL)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, + p)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, + q)) + || !TEST_true(OSSL_PARAM_BLD_push_int(bld, + OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ, 1)) + || !TEST_ptr(fromdata_params = OSSL_PARAM_BLD_to_param(bld))) + goto err; + + cdata[0].pname = OSSL_PKEY_PARAM_RSA_EXPONENT1; + cdata[0].comparebn = dmp1; + cdata[1].pname = OSSL_PKEY_PARAM_RSA_EXPONENT2; + cdata[1].comparebn = dmq1; + cdata[2].pname = OSSL_PKEY_PARAM_RSA_COEFFICIENT1; + cdata[2].comparebn = iqmp; + cdata[3].pname = NULL; + cdata[3].comparebn = NULL; + + ret = do_fromdata_rsa_derive(fromdata_params, cdata, 512, 56, 64); + +err: + BN_free(n); + BN_free(e); + BN_free(d); + BN_free(p); + BN_free(q); + BN_free(dmp1); + BN_free(dmq1); + BN_free(iqmp); + OSSL_PARAM_BLD_free(bld); + return ret; +} + +static int test_fromdata_rsa_derive_from_pq_multiprime(void) +{ + OSSL_PARAM_BLD *bld = NULL; + BIGNUM *n = NULL, *e = NULL, *d = NULL; + BIGNUM *p = NULL, *q = NULL, *p2 = NULL; + BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; + BIGNUM *exp3 = NULL, *coeff2 = NULL; + OSSL_PARAM *fromdata_params = NULL; + struct check_data cdata[12]; + int ret = 0; + /* + * multiprime RSA key, extracted from this command, + * openssl genrsa -primes 3 | openssl rsa -text + * Note: When generating a key with EVP_PKEY_fromdata, and using + * crt derivation, openssl requires a minimum of 512 bits of n data, + * and 2048 bits in the FIPS case + */ + static unsigned char n_data[] = + {0x00, 0x95, 0x78, 0x21, 0xe0, 0xca, 0x94, 0x6c, 0x0b, 0x86, 0x2a, 0x01, + 0xde, 0xd9, 0xab, 0xee, 0x88, 0x4a, 0x27, 0x4f, 0xcc, 0x5f, 0xf1, 0x71, + 0xe1, 0x0b, 0xc3, 0xd1, 0x88, 0x76, 0xf0, 0x83, 0x03, 0x93, 0x7e, 0x39, + 0xfa, 0x47, 0x89, 0x34, 0x27, 0x18, 0x19, 0x97, 0xfc, 0xd4, 0xfe, 0xe5, + 0x8a, 0xa9, 0x11, 0x83, 0xb5, 0x15, 0x4a, 0x29, 0xa6, 0xa6, 0xd0, 0x6e, + 0x0c, 0x7f, 0x61, 0x8f, 0x7e, 0x7c, 0xfb, 0xfc, 0x04, 0x8b, 0xca, 0x44, + 0xf8, 0x59, 0x0b, 0x22, 0x6f, 0x3f, 0x92, 0x23, 0x98, 0xb5, 0xc8, 0xf7, + 0xff, 0xf7, 0xac, 0x6b, 0x36, 0xb3, 0xaf, 0x39, 0xde, 0x66, 0x38, 0x51, + 0x9f, 0xbe, 0xe2, 0xfc, 0xe4, 0x6f, 0x1a, 0x0f, 0x7a, 0xde, 0x7f, 0x0f, + 0x4e, 0xbc, 0xed, 0xa2, 0x99, 0xc5, 0xd1, 0xbf, 0x8f, 0xba, 0x92, 0x91, + 0xe4, 0x00, 0x91, 0xbb, 0x67, 0x36, 0x7d, 0x00, 0x50, 0xda, 0x28, 0x38, + 0xdc, 0x9f, 0xfe, 0x3f, 0x24, 0x5a, 0x0d, 0xe1, 0x8d, 0xe9, 0x45, 0x2c, + 0xd7, 0xf2, 0x67, 0x8c, 0x0c, 0x6e, 0xdb, 0xc8, 0x8b, 0x6b, 0x38, 0x30, + 0x21, 0x94, 0xc0, 0xe3, 0xd7, 0xe0, 0x23, 0xd3, 0xd4, 0xfa, 0xdb, 0xb9, + 0xfe, 0x1a, 0xcc, 0xc9, 0x79, 0x19, 0x35, 0x18, 0x42, 0x30, 0xc4, 0xb5, + 0x92, 0x33, 0x1e, 0xd4, 0xc4, 0xc0, 0x9d, 0x55, 0x37, 0xd4, 0xef, 0x54, + 0x71, 0x81, 0x09, 0x15, 0xdb, 0x11, 0x38, 0x6b, 0x35, 0x93, 0x11, 0xdc, + 0xb1, 0x6c, 0xd6, 0xa4, 0x37, 0x84, 0xf3, 0xb2, 0x2f, 0x1b, 0xd6, 0x05, + 0x9f, 0x0e, 0x5c, 0x98, 0x29, 0x2f, 0x95, 0xb6, 0x55, 0xbd, 0x24, 0x44, + 0xc5, 0xc8, 0xa2, 0x76, 0x1e, 0xf8, 0x82, 0x8a, 0xdf, 0x34, 0x72, 0x7e, + 0xdd, 0x65, 0x4b, 0xfc, 0x6c, 0x1c, 0x96, 0x70, 0xe2, 0x69, 0xb5, 0x12, + 0x1b, 0x59, 0x67, 0x14, 0x9d}; + static unsigned char e_data[] = {0x01, 0x00, 0x01}; + static unsigned char d_data[] = + {0x64, 0x57, 0x4d, 0x86, 0xf6, 0xf8, 0x44, 0xc0, 0x47, 0xc5, 0x13, 0x94, + 0x63, 0x54, 0x84, 0xc1, 0x81, 0xe6, 0x7a, 0x2f, 0x9d, 0x89, 0x1d, 0x06, + 0x13, 0x3b, 0xd6, 0x02, 0x62, 0xb6, 0x7b, 0x7d, 0x7f, 0x1a, 0x92, 0x19, + 0x6e, 0xc4, 0xb0, 0xfa, 0x3d, 0xb7, 0x90, 0xcc, 0xee, 0xc0, 0x5f, 0xa0, + 0x82, 0x77, 0x7b, 0x8f, 0xa9, 0x47, 0x2c, 0x46, 0xf0, 0x5d, 0xa4, 0x43, + 0x47, 0x90, 0x5b, 0x20, 0x73, 0x0f, 0x46, 0xd4, 0x56, 0x73, 0xe7, 0x71, + 0x41, 0x75, 0xb4, 0x1c, 0x32, 0xf5, 0x0c, 0x68, 0x8c, 0x40, 0xea, 0x1c, + 0x30, 0x12, 0xa2, 0x65, 0x02, 0x27, 0x98, 0x4e, 0x0a, 0xbf, 0x2b, 0x72, + 0xb2, 0x5c, 0xe3, 0xbe, 0x3e, 0xc7, 0xdb, 0x9b, 0xa2, 0x4a, 0x90, 0xc0, + 0xa7, 0xb0, 0x00, 0xf1, 0x6a, 0xff, 0xa3, 0x77, 0xf7, 0x71, 0xa2, 0x41, + 0xe9, 0x6e, 0x7c, 0x38, 0x24, 0x46, 0xd5, 0x5c, 0x49, 0x2a, 0xe6, 0xee, + 0x27, 0x4b, 0x2e, 0x6f, 0x16, 0x54, 0x2d, 0x37, 0x36, 0x01, 0x39, 0x2b, + 0x23, 0x4b, 0xb4, 0x65, 0x25, 0x4d, 0x7f, 0x72, 0x20, 0x7f, 0x5d, 0xec, + 0x50, 0xba, 0xbb, 0xaa, 0x9c, 0x3c, 0x1d, 0xa1, 0x40, 0x2c, 0x6a, 0x8b, + 0x5f, 0x2e, 0xe0, 0xa6, 0xf7, 0x9e, 0x03, 0xb5, 0x44, 0x5f, 0x74, 0xc7, + 0x9f, 0x89, 0x2b, 0x71, 0x2f, 0x66, 0x9f, 0x03, 0x6c, 0x96, 0xd0, 0x23, + 0x36, 0x4d, 0xa1, 0xf0, 0x82, 0xcc, 0x43, 0xe7, 0x08, 0x93, 0x40, 0x18, + 0xc0, 0x39, 0x73, 0x83, 0xe2, 0xec, 0x9b, 0x81, 0x9d, 0x4c, 0x86, 0xaa, + 0x59, 0xa8, 0x67, 0x1c, 0x80, 0xdc, 0x6f, 0x7f, 0x23, 0x6b, 0x7d, 0x2c, + 0x56, 0x99, 0xa0, 0x89, 0x7e, 0xdb, 0x8b, 0x7a, 0xaa, 0x03, 0x8e, 0x8e, + 0x8e, 0x3a, 0x58, 0xb4, 0x03, 0x6b, 0x65, 0xfa, 0x92, 0x0a, 0x96, 0x93, + 0xa6, 0x07, 0x60, 0x01}; + static unsigned char p_data[] = + {0x06, 0x55, 0x7f, 0xbd, 0xfd, 0xa8, 0x4c, 0x94, 0x5e, 0x10, 0x8a, 0x54, + 0x37, 0xf3, 0x64, 0x37, 0x3a, 0xca, 0x18, 0x1b, 0xdd, 0x71, 0xa5, 0x94, + 0xc9, 0x31, 0x59, 0xa5, 0x89, 0xe9, 0xc4, 0xba, 0x55, 0x90, 0x6d, 0x9c, + 0xcc, 0x52, 0x5d, 0x44, 0xa8, 0xbc, 0x2b, 0x3b, 0x8c, 0xbd, 0x96, 0xfa, + 0xcd, 0x54, 0x63, 0xe3, 0xc8, 0xfe, 0x5e, 0xc6, 0x73, 0x98, 0x14, 0x7a, + 0x54, 0x0e, 0xe7, 0x75, 0x49, 0x93, 0x20, 0x33, 0x17, 0xa9, 0x34, 0xa8, + 0xee, 0xaf, 0x3a, 0xcc, 0xf5, 0x69, 0xfc, 0x30, 0x1a, 0xdf, 0x49, 0x61, + 0xa4, 0xd1}; + static unsigned char p2_data[] = + {0x03, 0xe2, 0x41, 0x3d, 0xb1, 0xdd, 0xad, 0xd7, 0x3b, 0xf8, 0xab, 0x32, + 0x27, 0x8b, 0xac, 0x95, 0xc0, 0x1a, 0x3f, 0x80, 0x8e, 0x21, 0xa9, 0xb8, + 0xa2, 0xed, 0xcf, 0x97, 0x5c, 0x61, 0x10, 0x94, 0x1b, 0xd0, 0xbe, 0x88, + 0xc2, 0xa7, 0x20, 0xe5, 0xa5, 0xc2, 0x7a, 0x7e, 0xf0, 0xd1, 0xe4, 0x13, + 0x75, 0xb9, 0x62, 0x90, 0xf1, 0xc3, 0x5b, 0x8c, 0xe9, 0xa9, 0x5b, 0xb7, + 0x6d, 0xdc, 0xcd, 0x12, 0xea, 0x97, 0x05, 0x04, 0x25, 0x2a, 0x93, 0xd1, + 0x4e, 0x05, 0x1a, 0x50, 0xa2, 0x67, 0xb8, 0x4b, 0x09, 0x15, 0x65, 0x6c, + 0x66, 0x2d}; + static unsigned char q_data[] = + {0x06, 0x13, 0x74, 0x6e, 0xde, 0x7c, 0x33, 0xc2, 0xe7, 0x05, 0x2c, 0xeb, + 0x25, 0x7d, 0x4a, 0x07, 0x7e, 0x03, 0xcf, 0x6a, 0x23, 0x36, 0x25, 0x23, + 0xf6, 0x5d, 0xde, 0xa3, 0x0f, 0x82, 0xe6, 0x4b, 0xec, 0x39, 0xbf, 0x37, + 0x1f, 0x4f, 0x56, 0x1e, 0xd8, 0x62, 0x32, 0x5c, 0xf5, 0x37, 0x75, 0x20, + 0xe2, 0x7e, 0x56, 0x82, 0xc6, 0x35, 0xd3, 0x4d, 0xfa, 0x6c, 0xc3, 0x93, + 0xf0, 0x60, 0x53, 0x78, 0x95, 0xee, 0xf9, 0x8b, 0x2c, 0xaf, 0xb1, 0x47, + 0x5c, 0x29, 0x0d, 0x2a, 0x47, 0x7f, 0xd0, 0x7a, 0x4e, 0x26, 0x7b, 0x47, + 0xfb, 0x61}; + static unsigned char dmp1_data[] = + {0x01, 0x13, 0x3a, 0x1f, 0x91, 0x92, 0xa3, 0x8c, 0xfb, 0x7a, 0x6b, 0x40, + 0x68, 0x4e, 0xd3, 0xcf, 0xdc, 0x16, 0xb9, 0x88, 0xe1, 0x49, 0x8d, 0x05, + 0x78, 0x30, 0xfc, 0x3a, 0x70, 0xf2, 0x51, 0x06, 0x1f, 0xc7, 0xe8, 0x13, + 0x19, 0x4b, 0x51, 0xb1, 0x79, 0xc2, 0x96, 0xc4, 0x00, 0xdb, 0x9d, 0x68, + 0xec, 0xb9, 0x4a, 0x4b, 0x3b, 0xae, 0x91, 0x7f, 0xb5, 0xd7, 0x36, 0x82, + 0x9d, 0x09, 0xfa, 0x97, 0x99, 0xe9, 0x73, 0x29, 0xb8, 0xf6, 0x6b, 0x8d, + 0xd1, 0x15, 0xc5, 0x31, 0x4c, 0xe6, 0xb4, 0x7b, 0xa5, 0xd4, 0x08, 0xac, + 0x9e, 0x41}; + static unsigned char dmq1_data[] = + {0x05, 0xcd, 0x33, 0xc2, 0xdd, 0x3b, 0xb8, 0xec, 0xe4, 0x4c, 0x03, 0xcc, + 0xef, 0xba, 0x07, 0x22, 0xca, 0x47, 0x77, 0x18, 0x40, 0x50, 0xe5, 0xfb, + 0xc5, 0xb5, 0x71, 0xed, 0x3e, 0xd5, 0x5d, 0x72, 0xa7, 0x37, 0xa8, 0x86, + 0x48, 0xa6, 0x27, 0x74, 0x42, 0x66, 0xd8, 0xf1, 0xfb, 0xcf, 0x1d, 0x4e, + 0xee, 0x15, 0x76, 0x23, 0x5e, 0x81, 0x6c, 0xa7, 0x2b, 0x74, 0x08, 0xf7, + 0x4c, 0x71, 0x9d, 0xa2, 0x29, 0x7f, 0xca, 0xd5, 0x02, 0x31, 0x2c, 0x54, + 0x18, 0x02, 0xb6, 0xa8, 0x65, 0x26, 0xfc, 0xf8, 0x9b, 0x80, 0x90, 0xfc, + 0x75, 0x61}; + static unsigned char iqmp_data[] = + {0x05, 0x78, 0xf8, 0xdd, 0x1c, 0x6f, 0x3d, 0xaf, 0x53, 0x84, 0x32, 0xa9, + 0x35, 0x52, 0xf3, 0xd0, 0x4d, 0xf8, 0x09, 0x85, 0x3d, 0x72, 0x20, 0x8b, + 0x47, 0xba, 0xc8, 0xce, 0xac, 0xd9, 0x76, 0x90, 0x05, 0x88, 0x63, 0x8a, + 0x10, 0x2b, 0xcd, 0xd3, 0xbe, 0x8c, 0x16, 0x60, 0x6a, 0xfd, 0xce, 0xc7, + 0x9f, 0xfa, 0xbb, 0xe3, 0xa6, 0xde, 0xc2, 0x8f, 0x1d, 0x25, 0xdc, 0x41, + 0xcb, 0xa4, 0xeb, 0x76, 0xc9, 0xdc, 0x8e, 0x49, 0x0e, 0xe4, 0x7c, 0xd2, + 0xd5, 0x6e, 0x26, 0x3c, 0x0b, 0xd3, 0xc5, 0x20, 0x4e, 0x4b, 0xb6, 0xf7, + 0xae, 0xef}; + static unsigned char exp3_data[] = + {0x02, 0x7d, 0x16, 0x24, 0xfc, 0x35, 0xf9, 0xd0, 0xb3, 0x02, 0xf2, 0x5f, + 0xde, 0xeb, 0x27, 0x19, 0x85, 0xd0, 0xcb, 0xe4, 0x0a, 0x2f, 0x13, 0xdb, + 0xd5, 0xba, 0xe0, 0x8c, 0x32, 0x8b, 0x97, 0xdd, 0xef, 0xbc, 0xe0, 0x7a, + 0x2d, 0x90, 0x7e, 0x09, 0xe9, 0x1f, 0x26, 0xf2, 0xf4, 0x48, 0xea, 0x06, + 0x76, 0x26, 0xe6, 0x3b, 0xce, 0x4e, 0xc9, 0xf9, 0x0f, 0x38, 0x90, 0x26, + 0x87, 0x65, 0x36, 0x9a, 0xea, 0x6a, 0xfe, 0xb1, 0xdb, 0x46, 0xdf, 0x14, + 0xfd, 0x13, 0x53, 0xfb, 0x5b, 0x35, 0x6e, 0xe7, 0xd5, 0xd8, 0x39, 0xf7, + 0x2d, 0xb9}; + static unsigned char coeff2_data[] = + {0x01, 0xba, 0x66, 0x0a, 0xa2, 0x86, 0xc0, 0x57, 0x7f, 0x4e, 0x68, 0xb1, + 0x86, 0x63, 0x23, 0x5b, 0x0e, 0xeb, 0x93, 0x42, 0xd1, 0xaa, 0x15, 0x13, + 0xcc, 0x29, 0x71, 0x8a, 0xb0, 0xe0, 0xc9, 0x67, 0xde, 0x1a, 0x7c, 0x1a, + 0xef, 0xa7, 0x08, 0x85, 0xb3, 0xae, 0x98, 0x99, 0xde, 0xaf, 0x09, 0x38, + 0xfc, 0x46, 0x29, 0x5f, 0x4f, 0x7e, 0x01, 0x6c, 0x50, 0x13, 0x95, 0x91, + 0x4c, 0x0f, 0x00, 0xba, 0xca, 0x40, 0xa3, 0xd0, 0x58, 0xb6, 0x62, 0x4c, + 0xd1, 0xb6, 0xd3, 0x29, 0x5d, 0x82, 0xb3, 0x3d, 0x61, 0xbe, 0x5d, 0xf0, + 0x4b, 0xf4}; + + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()) + || !TEST_ptr(n = BN_bin2bn(n_data, sizeof(n_data), NULL)) + || !TEST_ptr(e = BN_bin2bn(e_data, sizeof(e_data), NULL)) + || !TEST_ptr(d = BN_bin2bn(d_data, sizeof(d_data), NULL)) + || !TEST_ptr(p = BN_bin2bn(p_data, sizeof(p_data), NULL)) + || !TEST_ptr(q = BN_bin2bn(q_data, sizeof(q_data), NULL)) + || !TEST_ptr(p2 = BN_bin2bn(p2_data, sizeof(p2_data), NULL)) + || !TEST_ptr(exp3 = BN_bin2bn(exp3_data, sizeof(exp3_data), NULL)) + || !TEST_ptr(coeff2 = BN_bin2bn(coeff2_data, sizeof(coeff2_data), NULL)) + || !TEST_ptr(dmp1 = BN_bin2bn(dmp1_data, sizeof(dmp1_data), NULL)) + || !TEST_ptr(dmq1 = BN_bin2bn(dmq1_data, sizeof(dmq1_data), NULL)) + || !TEST_ptr(iqmp = BN_bin2bn(iqmp_data, sizeof(iqmp_data), NULL)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, + p)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, + q)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR3, + p2)) + || !TEST_true(OSSL_PARAM_BLD_push_int(bld, + OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ, 1)) + || !TEST_ptr(fromdata_params = OSSL_PARAM_BLD_to_param(bld))) + goto err; + + cdata[0].pname = OSSL_PKEY_PARAM_RSA_EXPONENT1; + cdata[0].comparebn = dmp1; + cdata[1].pname = OSSL_PKEY_PARAM_RSA_EXPONENT2; + cdata[1].comparebn = dmq1; + cdata[2].pname = OSSL_PKEY_PARAM_RSA_COEFFICIENT1; + cdata[2].comparebn = iqmp; + cdata[3].pname = OSSL_PKEY_PARAM_RSA_EXPONENT3; + cdata[3].comparebn = exp3; + cdata[4].pname = OSSL_PKEY_PARAM_RSA_COEFFICIENT2; + cdata[4].comparebn = coeff2; + cdata[5].pname = OSSL_PKEY_PARAM_RSA_N; + cdata[5].comparebn = n; + cdata[6].pname = OSSL_PKEY_PARAM_RSA_E; + cdata[6].comparebn = e; + cdata[7].pname = OSSL_PKEY_PARAM_RSA_D; + cdata[7].comparebn = d; + cdata[8].pname = OSSL_PKEY_PARAM_RSA_FACTOR1; + cdata[8].comparebn = p; + cdata[9].pname = OSSL_PKEY_PARAM_RSA_FACTOR2; + cdata[9].comparebn = q; + cdata[10].pname = OSSL_PKEY_PARAM_RSA_FACTOR3; + cdata[10].comparebn = p2; + cdata[11].pname = NULL; + cdata[11].comparebn = NULL; + + ret = do_fromdata_rsa_derive(fromdata_params, cdata, 2048, 112, 256); + +err: + BN_free(n); + BN_free(e); + BN_free(d); + BN_free(p); + BN_free(p2); + BN_free(q); + BN_free(dmp1); + BN_free(dmq1); + BN_free(iqmp); + BN_free(exp3); + BN_free(coeff2); + OSSL_PARAM_BLD_free(bld); + return ret; +} + static int test_evp_pkey_get_bn_param_large(void) { int ret = 0; @@ -459,7 +851,7 @@ static int test_evp_pkey_get_bn_param_large(void) static const unsigned char e_data[] = { 0x1, 0x00, 0x01 }; - static const unsigned char d_data[]= { + static const unsigned char d_data[] = { 0x99, 0x33, 0x13, 0x7b }; @@ -1765,6 +2157,8 @@ int setup_tests(void) ADD_TEST(test_evp_pkey_ctx_dup_kdf); ADD_TEST(test_evp_pkey_get_bn_param_large); ADD_TEST(test_fromdata_rsa); + ADD_TEST(test_fromdata_rsa_derive_from_pq_sp800); + ADD_TEST(test_fromdata_rsa_derive_from_pq_multiprime); #ifndef OPENSSL_NO_DH ADD_TEST(test_fromdata_dh_fips186_4); ADD_TEST(test_fromdata_dh_named_group); diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index c37ed7815f350..df93202d1d82b 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -348,6 +348,7 @@ my %params = ( 'PKEY_PARAM_RSA_MASKGENFUNC' => '*PKEY_PARAM_MASKGENFUNC', 'PKEY_PARAM_RSA_MGF1_DIGEST' => '*PKEY_PARAM_MGF1_DIGEST', 'PKEY_PARAM_RSA_PSS_SALTLEN' => "saltlen", + 'PKEY_PARAM_RSA_DERIVE_FROM_PQ' => "rsa-derive-from-pq", # EC, X25519 and X448 Key generation parameters 'PKEY_PARAM_DHKEM_IKM' => "dhkem-ikm", From 5dc2b72df76cf21095bd6a34449feb8474d85368 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 4 Jan 2024 10:07:17 +0100 Subject: [PATCH 36/81] Sync CHANGES.md and NEWS.md with 3.2 branch Reviewed-by: Matt Caswell Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/23200) --- CHANGES.md | 12 +++++++----- NEWS.md | 6 +++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 57507381e13e5..031c7101f8c0d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,11 +28,6 @@ OpenSSL 3.3 ### Changes between 3.2 and 3.3 [xx XXX xxxx] - * Disable building QUIC server utility when OpenSSL is configured with - `no-apps` - - *Vitalii Koshura* - * The activate and soft_load configuration settings for providers in openssl.cnf have been updated to require a value of [1|yes|true|on] (in lower or UPPER case) to enable the setting. Conversely a value @@ -78,6 +73,13 @@ OpenSSL 3.3 OpenSSL 3.2 ----------- +### Changes between 3.2.0 and 3.2.1 [xx XXX xxxx] + + * Disable building QUIC server utility when OpenSSL is configured with + `no-apps`. + + *Vitalii Koshura* + ### Changes between 3.1 and 3.2 [xx XXX xxxx] * The EVP_PKEY_fromdata function has been augmented to allow for the derivation diff --git a/NEWS.md b/NEWS.md index f85a87657c047..6f619a14deafa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,7 +29,11 @@ OpenSSL 3.3 OpenSSL 3.2 ----------- -### Major changes between OpenSSL 3.1 and OpenSSL 3.2 [under development] +### Major changes between OpenSSL 3.2.0 and OpenSSL 3.2.1 [under development] + + * none + +### Major changes between OpenSSL 3.1 and OpenSSL 3.2.0 [23 Nov 2023] OpenSSL 3.2.0 is a feature release adding significant new functionality to OpenSSL. From 8d847a3ffd4f0b17ee33962cf69c36224925b34f Mon Sep 17 00:00:00 2001 From: Rohan McLure Date: Thu, 4 Jan 2024 10:25:50 +0100 Subject: [PATCH 37/81] poly1305-ppc.pl: Fix vector register clobbering Fixes CVE-2023-6129 The POLY1305 MAC (message authentication code) implementation in OpenSSL for PowerPC CPUs saves the the contents of vector registers in different order than they are restored. Thus the contents of some of these vector registers is corrupted when returning to the caller. The vulnerable code is used only on newer PowerPC processors supporting the PowerISA 2.07 instructions. Reviewed-by: Matt Caswell Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23200) --- crypto/poly1305/asm/poly1305-ppc.pl | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/crypto/poly1305/asm/poly1305-ppc.pl b/crypto/poly1305/asm/poly1305-ppc.pl index 9f86134d923fb..2e601bb9c24be 100755 --- a/crypto/poly1305/asm/poly1305-ppc.pl +++ b/crypto/poly1305/asm/poly1305-ppc.pl @@ -744,7 +744,7 @@ my $LOCALS= 6*$SIZE_T; my $VSXFRAME = $LOCALS + 6*$SIZE_T; $VSXFRAME += 128; # local variables - $VSXFRAME += 13*16; # v20-v31 offload + $VSXFRAME += 12*16; # v20-v31 offload my $BIG_ENDIAN = ($flavour !~ /le/) ? 4 : 0; @@ -919,12 +919,12 @@ addi r11,r11,32 stvx v22,r10,$sp addi r10,r10,32 - stvx v23,r10,$sp - addi r10,r10,32 - stvx v24,r11,$sp + stvx v23,r11,$sp addi r11,r11,32 - stvx v25,r10,$sp + stvx v24,r10,$sp addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 stvx v26,r10,$sp addi r10,r10,32 stvx v27,r11,$sp @@ -1153,12 +1153,12 @@ addi r11,r11,32 stvx v22,r10,$sp addi r10,r10,32 - stvx v23,r10,$sp - addi r10,r10,32 - stvx v24,r11,$sp + stvx v23,r11,$sp addi r11,r11,32 - stvx v25,r10,$sp + stvx v24,r10,$sp addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 stvx v26,r10,$sp addi r10,r10,32 stvx v27,r11,$sp @@ -1899,26 +1899,26 @@ mtspr 256,r12 # restore vrsave lvx v20,r10,$sp addi r10,r10,32 - lvx v21,r10,$sp - addi r10,r10,32 - lvx v22,r11,$sp + lvx v21,r11,$sp addi r11,r11,32 - lvx v23,r10,$sp + lvx v22,r10,$sp addi r10,r10,32 - lvx v24,r11,$sp + lvx v23,r11,$sp addi r11,r11,32 - lvx v25,r10,$sp + lvx v24,r10,$sp addi r10,r10,32 - lvx v26,r11,$sp + lvx v25,r11,$sp addi r11,r11,32 - lvx v27,r10,$sp + lvx v26,r10,$sp addi r10,r10,32 - lvx v28,r11,$sp + lvx v27,r11,$sp addi r11,r11,32 - lvx v29,r10,$sp + lvx v28,r10,$sp addi r10,r10,32 - lvx v30,r11,$sp - lvx v31,r10,$sp + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp $POP r27,`$VSXFRAME-$SIZE_T*5`($sp) $POP r28,`$VSXFRAME-$SIZE_T*4`($sp) $POP r29,`$VSXFRAME-$SIZE_T*3`($sp) From 858c7bc210a406cc7f891ac2aed78692d2e02937 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 4 Jan 2024 10:32:32 +0100 Subject: [PATCH 38/81] Add CHANGES.md and NEWS.md entries for CVE-2023-6129 Reviewed-by: Matt Caswell Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/23200) --- CHANGES.md | 21 +++++++++++++++++++++ NEWS.md | 5 ++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 031c7101f8c0d..43b02502d8e01 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -75,6 +75,26 @@ OpenSSL 3.2 ### Changes between 3.2.0 and 3.2.1 [xx XXX xxxx] + * The POLY1305 MAC (message authentication code) implementation in OpenSSL + for PowerPC CPUs saves the contents of vector registers in different + order than they are restored. Thus the contents of some of these vector + registers is corrupted when returning to the caller. The vulnerable code is + used only on newer PowerPC processors supporting the PowerISA 2.07 + instructions. + + The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the + application process. However unless the compiler uses the vector registers + for storing pointers, the most likely consequence, if any, would be an + incorrect result of some application dependent calculations or a crash + leading to a denial of service. + + ([CVE-2023-6129]) + + *Rohan McLure* + * Disable building QUIC server utility when OpenSSL is configured with `no-apps`. @@ -20380,6 +20400,7 @@ ndif +[CVE-2023-6129]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6129 [CVE-2023-5678]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5678 [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 diff --git a/NEWS.md b/NEWS.md index 6f619a14deafa..a41353e1a6fce 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,7 +31,9 @@ OpenSSL 3.2 ### Major changes between OpenSSL 3.2.0 and OpenSSL 3.2.1 [under development] - * none + * Fix POLY1305 MAC implementation corrupting vector registers on PowerPC + CPUs which support PowerISA 2.07 + ([CVE-2023-6129]) ### Major changes between OpenSSL 3.1 and OpenSSL 3.2.0 [23 Nov 2023] @@ -1580,6 +1582,7 @@ OpenSSL 0.9.x +[CVE-2023-6129]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6129 [CVE-2023-5678]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5678 [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 From 806bbafe2df5b699feac6ef26e50c14e701950cf Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 18 Dec 2023 10:55:25 -0500 Subject: [PATCH 39/81] Check appropriate OSSL_PARAM_get_* functions for NULL The base type OSSL_PARAM getters will NULL deref if they are initalized as null. Add NULL checks for those parameters that have no expectation of returning null (int32/64/uint32/64/BN). Other types can be left as allowing NULL, as a NULL setting may be meaningful (string, utf8str, octet string, etc). Reviewed-by: Matt Caswell Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23083) --- crypto/params.c | 33 +++++++++++++++-- test/params_api_test.c | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/crypto/params.c b/crypto/params.c index f2582b0927a16..425c402fd53c5 100644 --- a/crypto/params.c +++ b/crypto/params.c @@ -197,6 +197,10 @@ static int unsigned_from_unsigned(void *dest, size_t dest_len, /* General purpose get integer parameter call that handles odd sizes */ static int general_get_int(const OSSL_PARAM *p, void *val, size_t val_size) { + if (p->data == NULL) { + err_null_argument; + return 0; + } if (p->data_type == OSSL_PARAM_INTEGER) return signed_from_signed(val, val_size, p->data, p->data_size); if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER) @@ -226,6 +230,11 @@ static int general_set_int(OSSL_PARAM *p, void *val, size_t val_size) /* General purpose get unsigned integer parameter call that handles odd sizes */ static int general_get_uint(const OSSL_PARAM *p, void *val, size_t val_size) { + + if (p->data == NULL) { + err_null_argument; + return 0; + } if (p->data_type == OSSL_PARAM_INTEGER) return unsigned_from_signed(val, val_size, p->data, p->data_size); if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER) @@ -385,6 +394,11 @@ int OSSL_PARAM_get_int32(const OSSL_PARAM *p, int32_t *val) return 0; } + if (p->data == NULL) { + err_null_argument; + return 0; + } + if (p->data_type == OSSL_PARAM_INTEGER) { #ifndef OPENSSL_SMALL_FOOTPRINT int64_t i64; @@ -534,6 +548,11 @@ int OSSL_PARAM_get_uint32(const OSSL_PARAM *p, uint32_t *val) return 0; } + if (p->data == NULL) { + err_null_argument; + return 0; + } + if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER) { #ifndef OPENSSL_SMALL_FOOTPRINT uint64_t u64; @@ -685,6 +704,11 @@ int OSSL_PARAM_get_int64(const OSSL_PARAM *p, int64_t *val) return 0; } + if (p->data == NULL) { + err_null_argument; + return 0; + } + if (p->data_type == OSSL_PARAM_INTEGER) { #ifndef OPENSSL_SMALL_FOOTPRINT switch (p->data_size) { @@ -829,6 +853,11 @@ int OSSL_PARAM_get_uint64(const OSSL_PARAM *p, uint64_t *val) return 0; } + if (p->data == NULL) { + err_null_argument; + return 0; + } + if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER) { #ifndef OPENSSL_SMALL_FOOTPRINT switch (p->data_size) { @@ -1040,7 +1069,7 @@ int OSSL_PARAM_get_BN(const OSSL_PARAM *p, BIGNUM **val) { BIGNUM *b = NULL; - if (val == NULL || p == NULL) { + if (val == NULL || p == NULL || p->data == NULL) { err_null_argument; return 0; } @@ -1132,7 +1161,7 @@ int OSSL_PARAM_get_double(const OSSL_PARAM *p, double *val) int64_t i64; uint64_t u64; - if (val == NULL || p == NULL) { + if (val == NULL || p == NULL || p->data == NULL) { err_null_argument; return 0; } diff --git a/test/params_api_test.c b/test/params_api_test.c index f4227b0012fa5..941b05c4d38dc 100644 --- a/test/params_api_test.c +++ b/test/params_api_test.c @@ -70,6 +70,49 @@ static const struct { 0x89, 0x67, 0xf2, 0x68, 0x33, 0xa0, 0x14, 0xb0 } }, }; +static int test_param_type_null(OSSL_PARAM *param) +{ + int rc = 0; + uint64_t intval; + double dval; + BIGNUM *bn; + + switch(param->data_type) { + case OSSL_PARAM_INTEGER: + if (param->data_size == sizeof(int32_t)) + rc = OSSL_PARAM_get_int32(param, (int32_t *)&intval); + else if (param->data_size == sizeof(uint64_t)) + rc = OSSL_PARAM_get_int64(param, (int64_t *)&intval); + else + return 1; + break; + case OSSL_PARAM_UNSIGNED_INTEGER: + if (param->data_size == sizeof(uint32_t)) + rc = OSSL_PARAM_get_uint32(param, (uint32_t *)&intval); + else if (param->data_size == sizeof(uint64_t)) + rc = OSSL_PARAM_get_uint64(param, &intval); + else + rc = OSSL_PARAM_get_BN(param, &bn); + break; + case OSSL_PARAM_REAL: + rc = OSSL_PARAM_get_double(param, &dval); + break; + case OSSL_PARAM_UTF8_STRING: + case OSSL_PARAM_OCTET_STRING: + case OSSL_PARAM_UTF8_PTR: + case OSSL_PARAM_OCTET_PTR: + /* these are allowed to be null */ + return 1; + break; + } + + /* + * we expect the various OSSL_PARAM_get functions above + * to return failure when the data is set to NULL + */ + return rc == 0; +} + static int test_param_type_extra(OSSL_PARAM *param, const unsigned char *cmp, size_t width) { @@ -157,6 +200,9 @@ static int test_param_int(int n) sizeof(int) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_int("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -184,6 +230,9 @@ static int test_param_long(int n) ? sizeof(long int) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_long("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -210,6 +259,9 @@ static int test_param_uint(int n) const size_t len = raw_values[n].len >= sizeof(unsigned int) ? sizeof(unsigned int) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_uint("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -237,6 +289,9 @@ static int test_param_ulong(int n) ? sizeof(unsigned long int) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_ulong("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -264,6 +319,9 @@ static int test_param_int32(int n) ? sizeof(int32_t) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_int32("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -291,6 +349,9 @@ static int test_param_uint32(int n) ? sizeof(uint32_t) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_uint32("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -318,6 +379,9 @@ static int test_param_int64(int n) ? sizeof(int64_t) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_int64("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -345,6 +409,9 @@ static int test_param_uint64(int n) ? sizeof(uint64_t) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_uint64("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -372,6 +439,9 @@ static int test_param_size_t(int n) ? sizeof(size_t) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_size_t("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -399,6 +469,9 @@ static int test_param_time_t(int n) ? sizeof(time_t) : raw_values[n].len; OSSL_PARAM param = OSSL_PARAM_time_t("a", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + memset(buf, 0, sizeof(buf)); le_copy(buf, sizeof(in), raw_values[n].value, sizeof(in)); memcpy(&in, buf, sizeof(in)); @@ -427,6 +500,9 @@ static int test_param_bignum(int n) NULL, 0); int ret = 0; + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + param.data = bnbuf; param.data_size = sizeof(bnbuf); @@ -458,6 +534,9 @@ static int test_param_signed_bignum(int n) OSSL_PARAM param = OSSL_PARAM_DEFN("bn", OSSL_PARAM_INTEGER, NULL, 0); int ret = 0; + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + param.data = bnbuf; param.data_size = sizeof(bnbuf); @@ -491,6 +570,9 @@ static int test_param_real(void) double p; OSSL_PARAM param = OSSL_PARAM_double("r", NULL); + if (!TEST_int_eq(test_param_type_null(¶m), 1)) + return 0; + param.data = &p; return TEST_true(OSSL_PARAM_set_double(¶m, 3.14159)) && TEST_double_eq(p, 3.14159); From 1d1ca79fe35dbe5c05faed5a2ef8c4de9c5adc49 Mon Sep 17 00:00:00 2001 From: "fangming.fang" Date: Mon, 8 Jan 2024 09:35:46 +0000 Subject: [PATCH 40/81] Preserve callee-saved registers in aarch64 AES-CTR code The AES-CTR assembly code uses v8-v15 registers, they are callee-saved registers, they must be preserved before the use and restored after the use. Change-Id: If9192d1f0f3cea7295f4b0d72ace88e6e8067493 Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23233) --- crypto/aes/asm/aesv8-armx.pl | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crypto/aes/asm/aesv8-armx.pl b/crypto/aes/asm/aesv8-armx.pl index 699ecfcd219d8..642d779b99acb 100755 --- a/crypto/aes/asm/aesv8-armx.pl +++ b/crypto/aes/asm/aesv8-armx.pl @@ -1780,8 +1780,12 @@ () ${prefix}_ctr32_encrypt_blocks_unroll12_eor3: AARCH64_VALID_CALL_TARGET // Armv8.3-A PAuth: even though x30 is pushed to stack it is not popped later. - stp x29,x30,[sp,#-16]! - add x29,sp,#0 + stp x29,x30,[sp,#-80]! + stp d8,d9,[sp, #16] + stp d10,d11,[sp, #32] + stp d12,d13,[sp, #48] + stp d14,d15,[sp, #64] + add x29,sp,#0 ldr $rounds,[$key,#240] @@ -2486,7 +2490,11 @@ () vst1.8 {$in0},[$out],#16 .Lctr32_done_unroll: - ldr x29,[sp],#16 + ldp d8,d9,[sp, #16] + ldp d10,d11,[sp, #32] + ldp d12,d13,[sp, #48] + ldp d15,d16,[sp, #64] + ldr x29,[sp],#80 ret .size ${prefix}_ctr32_encrypt_blocks_unroll12_eor3,.-${prefix}_ctr32_encrypt_blocks_unroll12_eor3 ___ From 0151e772195fc03cce0f12e5e266e51dc15243a0 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Mon, 8 Jan 2024 15:31:32 +0100 Subject: [PATCH 41/81] Fix a possible memory leak in sxnet_v2i When a subsequent call to SXNET_add_id_asc fails e.g. because user is a string larger than 64 char or the zone is a duplicate zone id, or the zone is not an integer, a memory leak may be the result. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23234) --- crypto/x509/v3_sxnet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crypto/x509/v3_sxnet.c b/crypto/x509/v3_sxnet.c index 36620a2b67457..b9ddfe324431a 100644 --- a/crypto/x509/v3_sxnet.c +++ b/crypto/x509/v3_sxnet.c @@ -103,8 +103,10 @@ static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, int i; for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { cnf = sk_CONF_VALUE_value(nval, i); - if (!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1)) + if (!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1)) { + SXNET_free(sx); return NULL; + } } return sx; } From 398011848468c7e8e481b295f7904afc30934217 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Tue, 9 Jan 2024 15:05:30 +0100 Subject: [PATCH 42/81] Fix a similar memory leak in SXNET_add_id_INTEGER Even in the good case there was memory leak here. Add a simple test case to have at least some test coverage. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23234) --- crypto/x509/v3_sxnet.c | 1 + test/recipes/25-test_req.t | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crypto/x509/v3_sxnet.c b/crypto/x509/v3_sxnet.c index b9ddfe324431a..74209d3e3f2de 100644 --- a/crypto/x509/v3_sxnet.c +++ b/crypto/x509/v3_sxnet.c @@ -204,6 +204,7 @@ int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, const char *user, ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB); goto err; } + ASN1_INTEGER_free(id->zone); id->zone = zone; *psx = sx; return 1; diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t index 20e338b46f4f5..50188cbae588c 100644 --- a/test/recipes/25-test_req.t +++ b/test/recipes/25-test_req.t @@ -15,7 +15,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_req"); -plan tests => 106; +plan tests => 107; require_ok(srctop_file('test', 'recipes', 'tconversion.pl')); @@ -52,6 +52,7 @@ ok(!run(app([@addext_args, "-addext", $val, "-addext", $val]))); ok(!run(app([@addext_args, "-addext", $val, "-addext", $val2]))); ok(!run(app([@addext_args, "-addext", $val, "-addext", $val3]))); ok(!run(app([@addext_args, "-addext", $val2, "-addext", $val3]))); +ok(run(app([@addext_args, "-addext", "SXNetID=1:one, 2:two, 3:three"]))); # If a CSR is provided with neither of -key or -CA/-CAkey, this should fail. ok(!run(app(["openssl", "req", "-x509", From 0a40b23cb86d41b27aea67c648e35cd420d39674 Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Wed, 3 Jan 2024 14:17:20 +0100 Subject: [PATCH 43/81] Remove wpend_ret that was only assigned and never used. Reviewed-by: Neil Horman Reviewed-by: Hugo Landau Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23191) --- ssl/record/rec_layer_s3.c | 2 -- ssl/record/record.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 845eff9848e5b..8a2db5817fd27 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -32,7 +32,6 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl) rl->handshake_fragment_len = 0; rl->wpend_tot = 0; rl->wpend_type = 0; - rl->wpend_ret = 0; rl->wpend_buf = NULL; if (rl->rrlmethod != NULL) @@ -310,7 +309,6 @@ int ssl3_write_bytes(SSL *ssl, uint8_t type, const void *buf_, size_t len, s->rlayer.wpend_tot = 0; s->rlayer.wpend_type = type; s->rlayer.wpend_buf = buf; - s->rlayer.wpend_ret = len; } if (tot == len) { /* done? */ diff --git a/ssl/record/record.h b/ssl/record/record.h index 6fb579fe19f14..9c83d6fa1fc0b 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -108,8 +108,6 @@ typedef struct record_layer_st { /* number bytes written */ size_t wpend_tot; uint8_t wpend_type; - /* number of bytes submitted */ - size_t wpend_ret; const unsigned char *wpend_buf; /* Count of the number of consecutive warning alerts received */ From ff7b32e1d7af590eab3163f0c6be7792876c36bc Mon Sep 17 00:00:00 2001 From: James Muir Date: Tue, 9 Jan 2024 22:38:43 -0500 Subject: [PATCH 44/81] doc: "digest" must be explicitly set with deterministic ECDSA/DSA Fixes #23205 Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23250) --- doc/man7/provider-signature.pod | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/man7/provider-signature.pod b/doc/man7/provider-signature.pod index 3e900677d319f..38d3320d18c88 100644 --- a/doc/man7/provider-signature.pod +++ b/doc/man7/provider-signature.pod @@ -365,12 +365,15 @@ signature algorithm and digest algorithm for the signature operation. =item "nonce-type" (B) -Set this to 1 to use a deterministic ECDSA or DSA digital signature as -defined in RFC #6979 (See Section 3.2 "Generation of k"). -The default value of 0 uses a random value for the nonce B as defined in -FIPS 186-4 Section 6.3 "Secret Number Generation". -Before using deterministic digital signature please read -RFC #6979 Section 4 "Security Considerations". +Set this to 1 to use deterministic digital signature generation with +ECDSA or DSA, as defined in RFC 6979 (see Section 3.2 "Generation of +k"). In this case, the "digest" parameter must be explicitly set +(otherwise, deterministic nonce generation will fail). Before using +deterministic digital signature generation, please read RFC 6979 +Section 4 "Security Considerations". The default value for +"nonce-type" is 0 and results in a random value being used for the +nonce B as defined in FIPS 186-4 Section 6.3 "Secret Number +Generation". =item "kat" (B) From da840c3775f52fc9766c654b5ad6ee031ffc9fd9 Mon Sep 17 00:00:00 2001 From: sashan Date: Mon, 8 Jan 2024 22:53:42 +0100 Subject: [PATCH 45/81] evp_fetch.c: Check meth_id instead of name_id Fixes #23226 Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23238) --- crypto/evp/evp_fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index bd816be5f4feb..7008f42549019 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -334,7 +334,7 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, method = NULL; } else { meth_id = evp_method_id(name_id, operation_id); - if (name_id != 0) + if (meth_id != 0) ossl_method_store_cache_set(store, prov, meth_id, propq, method, up_ref_method, free_method); } From 493ad484e9312b54d177d85e2f4aa0b636e708f0 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 29 Nov 2023 09:17:39 +0100 Subject: [PATCH 46/81] Disable build of HWAES on PPC Macs Fixes #22818 Reviewed-by: Neil Horman Reviewed-by: Todd Short Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22860) --- crypto/aes/build.info | 6 +++++- include/crypto/aes_platform.h | 18 +++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/crypto/aes/build.info b/crypto/aes/build.info index 2d33f82f23b9a..0849aadc0f3ac 100644 --- a/crypto/aes/build.info +++ b/crypto/aes/build.info @@ -38,7 +38,11 @@ IF[{- !$disabled{asm} -}] $AESASM_parisc20_64=$AESASM_parisc11 $AESDEF_parisc20_64=$AESDEF_parisc11 - $AESASM_ppc32=aes_core.c aes_cbc.c aes-ppc.s vpaes-ppc.s aesp8-ppc.s + IF[{- $target{sys_id} ne "AIX" && $target{sys_id} ne "MACOSX" -}] + $AESASM_ppc32=aes_core.c aes_cbc.c aes-ppc.s vpaes-ppc.s aesp8-ppc.s + ELSE + $AESASM_ppc32=aes_core.c aes_cbc.c aes-ppc.s vpaes-ppc.s + ENDIF $AESDEF_ppc32=AES_ASM VPAES_ASM $AESASM_ppc64=$AESASM_ppc32 $AESDEF_ppc64=$AESDEF_ppc32 diff --git a/include/crypto/aes_platform.h b/include/crypto/aes_platform.h index 8a9e7a0535170..51fc5ba2111c6 100644 --- a/include/crypto/aes_platform.h +++ b/include/crypto/aes_platform.h @@ -65,16 +65,16 @@ void AES_xts_decrypt(const unsigned char *inp, unsigned char *out, size_t len, # ifdef VPAES_ASM # define VPAES_CAPABLE (OPENSSL_ppccap_P & PPC_ALTIVEC) # endif -# define HWAES_CAPABLE (OPENSSL_ppccap_P & PPC_CRYPTO207) -# define HWAES_set_encrypt_key aes_p8_set_encrypt_key -# define HWAES_set_decrypt_key aes_p8_set_decrypt_key -# define HWAES_encrypt aes_p8_encrypt -# define HWAES_decrypt aes_p8_decrypt -# define HWAES_cbc_encrypt aes_p8_cbc_encrypt -# define HWAES_ctr32_encrypt_blocks aes_p8_ctr32_encrypt_blocks -# define HWAES_xts_encrypt aes_p8_xts_encrypt -# define HWAES_xts_decrypt aes_p8_xts_decrypt # if !defined(OPENSSL_SYS_AIX) && !defined(OPENSSL_SYS_MACOSX) +# define HWAES_CAPABLE (OPENSSL_ppccap_P & PPC_CRYPTO207) +# define HWAES_set_encrypt_key aes_p8_set_encrypt_key +# define HWAES_set_decrypt_key aes_p8_set_decrypt_key +# define HWAES_encrypt aes_p8_encrypt +# define HWAES_decrypt aes_p8_decrypt +# define HWAES_cbc_encrypt aes_p8_cbc_encrypt +# define HWAES_ctr32_encrypt_blocks aes_p8_ctr32_encrypt_blocks +# define HWAES_xts_encrypt aes_p8_xts_encrypt +# define HWAES_xts_decrypt aes_p8_xts_decrypt # define PPC_AES_GCM_CAPABLE (OPENSSL_ppccap_P & PPC_MADD300) # define AES_GCM_ENC_BYTES 128 # define AES_GCM_DEC_BYTES 128 From 7c1d533a512181b13de3bc0b7fa2fd8c481032d3 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 8 Jan 2024 14:29:52 -0500 Subject: [PATCH 47/81] Update Docs for EVP_MAC For GMAC/CMAC, its not possible to re-init the algorithm without explicitly passing an OSSL_MAC_PARAM_IV to each init call, as it is not possible to extract the IV value from the prior init call (be it explicitly passed or auto generated). As such, document the fact that re-initalization requires passing an IV parameter Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23235) --- doc/man3/EVP_MAC.pod | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/man3/EVP_MAC.pod b/doc/man3/EVP_MAC.pod index b91c6a5d292f4..7983e51fd10c9 100644 --- a/doc/man3/EVP_MAC.pod +++ b/doc/man3/EVP_MAC.pod @@ -145,6 +145,9 @@ the key. If I is NULL, the key must be set via I either as part of this call or separately using EVP_MAC_CTX_set_params(). Providing non-NULL I to this function is equivalent to calling EVP_MAC_CTX_set_params() with those I for the same I beforehand. +Note: There are additional requirements for some MAC algorithms during +re-initalization (i.e. calling EVP_MAC_init() on an EVP_MAC after EVP_MAC_final() +has been called on the same object). See the NOTES section below. EVP_MAC_init() should be called before EVP_MAC_update() and EVP_MAC_final(). @@ -344,6 +347,13 @@ not be considered a breaking change to the API. The usage of the parameter names "custom", "iv" and "salt" correspond to the names used in the standard where the algorithm was defined. +Some MAC algorithms store internal state that cannot be extracted during +re-initalization. For example GMAC cannot extract an B from the +underlying CIPHER context, and so calling EVP_MAC_init() on an EVP_MAC object +after EVP_MAC_final() has been called cannot reset its cipher state to what it +was when the B was initially generated. For such instances, an +B parameter must be passed with each call to EVP_MAC_init(). + =head1 RETURN VALUES EVP_MAC_fetch() returns a pointer to a newly fetched B, or From 63f77f0454791acbcd150b186988c11a3235882b Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Mon, 6 Nov 2023 13:42:04 +0000 Subject: [PATCH 48/81] QUIC RCIDM: Add RCIDM Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- include/internal/quic_rcidm.h | 171 ++++++++++ ssl/quic/build.info | 3 +- ssl/quic/quic_rcidm.c | 619 ++++++++++++++++++++++++++++++++++ 3 files changed, 792 insertions(+), 1 deletion(-) create mode 100644 include/internal/quic_rcidm.h create mode 100644 ssl/quic/quic_rcidm.c diff --git a/include/internal/quic_rcidm.h b/include/internal/quic_rcidm.h new file mode 100644 index 0000000000000..cd90d0948105f --- /dev/null +++ b/include/internal/quic_rcidm.h @@ -0,0 +1,171 @@ +/* +* 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_INTERNAL_QUIC_RCIDM_H +# define OSSL_INTERNAL_QUIC_RCIDM_H +# pragma once + +# include "internal/e_os.h" +# include "internal/time.h" +# include "internal/quic_types.h" +# include "internal/quic_wire.h" + +# ifndef OPENSSL_NO_QUIC + +/* + * QUIC Remote Connection ID Manager + * ================================= + * + * This manages connection IDs for the TX side, which is to say that it tracks + * remote CIDs (RCIDs) which a peer has issued to us and which we can use as the + * DCID of packets we transmit. It is entirely separate from the LCIDM, which + * handles routing received packets by their DCIDs. + * + * RCIDs fall into four categories: + * + * 1. A client's Initial ODCID (0..1) + * 2. A peer's Initial SCID (1) + * 3. A server's Retry SCID (0..1) + * 4. A CID issued via a NEW_CONNECTION_ID frame (n) + * + * Unlike a LCIDM, which is per port, a RCIDM is per connection, as there is no + * need for routing of outgoing packets. + */ +typedef struct quic_rcidm_st QUIC_RCIDM; + +/* + * Creates a new RCIDM. Returns NULL on failure. + * + * For a client, initial_rcid is the client's Initial ODCID. + * For a server, initial_rcid is NULL. + */ +QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid); + +/* Frees a RCIDM. */ +void ossl_quic_rcidm_free(QUIC_RCIDM *rcidm); + +/* + * CID Events + * ========== + */ + +/* + * To be called by a client when a server responds to the first Initial packet + * sent with its own Initial packet with its own SCID; or to be called by a + * server when we first get an Initial packet from a client with the client's + * supplied SCID. The added RCID implicitly has a sequence number of 0. + * + * We immediately switch to using this SCID as our preferred RCID. This SCID + * must be enrolled using this function. May only be called once. + */ +int ossl_quic_rcidm_add_from_initial(QUIC_RCIDM *rcidm, + const QUIC_CONN_ID *rcid); + +/* + * To be called by a client when a server responds to the first Initial packet + * sent with a Retry packet with its own SCID (the "Retry ODCID"). We + * immediately switch to using this SCID as our preferred RCID when conducting + * the retry. This SCID must be enrolled using this function. May only be called + * once. The added RCID has no sequence number associated with it as it is + * essentially a new ODCID (hereafter a Retry ODCID). + * + * Not for server use. + */ +int ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM *rcidm, + const QUIC_CONN_ID *retry_odcid); + +/* + * Processes an incoming NEW_CONN_ID frame, recording the new CID as a potential + * RCID. The RCIDM retirement mechanism is ratcheted according to the + * ncid->retire_prior_to field. The stateless_reset field is ignored; the caller + * is responsible for handling it separately. + */ +int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm, + const OSSL_QUIC_FRAME_NEW_CONN_ID *ncid); + +/* + * Other Events + * ============ + */ + +/* + * Notifies the RCIDM that the handshake for a connection is complete. + * Should only be called once; further calls are ignored. + * + * This may influence the RCIDM's RCID change policy. + */ +void ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM *rcidm); + +/* + * Notifies the RCIDM that one or more packets have been sent. + * + * This may influence the RCIDM's RCID change policy. + */ +void ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM *rcidm, uint64_t num_packets); + +/* + * Manually request switching to a new RCID as soon as possible. + */ +void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm); + +/* + * Queries + * ======= + */ + +/* + * The RCIDM decides when it will never use a given RCID again. When it does + * this, it outputs the sequence number of that RCID using this function, which + * pops from a logical queue of retired RCIDs. The caller is responsible + * for polling this function and generating Retire CID frames from the result. + * + * If nothing needs doing and the queue is empty, this function returns 0. If + * there is an RCID which needs retiring, the sequence number of that RCID is + * written to *seq_num (if seq_num is non-NULL) and this function returns 1. The + * queue entry is popped (and the caller is thus assumed to have taken + * responsibility for transmitting the necessary Retire CID frame). + * + * Note that the caller should not transmit a Retire CID frame immediately as + * packets using the RCID may still be in flight. The caller must determine an + * appropriate delay using knowledge of network conditions (RTT, etc.) which is + * outside the scope of the RCIDM. The caller is responsible for implementing + * this delay. + */ +int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcid, uint64_t *seq_num); + +/* + * Like ossl_quic_rcidm_pop_retire_seek_num, but does not pop the item from the + * queue. If this call succeeds, the next call to + * ossl_quic_rcidm_pop_retire_seq_num is guaranteed to output the same sequence + * number. + */ +int ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM *rcid, uint64_t *seq_num); + +/* + * Writes the DCID preferred for a newly transmitted packet at this time to + * *tx_dcid. This function should be called to determine what DCID to use when + * transmitting a packet to the peer. The RCIDM may implement arbitrary policy + * to decide when to change the preferred RCID. + * + * Returns 1 on success and 0 on failure. + */ +int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm, + QUIC_CONN_ID *tx_dcid); + +/* + * Returns 1 if the value output by ossl_quic_rcidm_get_preferred_tx_dcid() has + * changed since the last call to this function with clear set. If clear is set, + * clears the changed flag. Returns the old value of the changed flag. + */ +int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm, + int clear); + +# endif + +#endif diff --git a/ssl/quic/build.info b/ssl/quic/build.info index 9927d344d8eb7..6cdb0b761b745 100644 --- a/ssl/quic/build.info +++ b/ssl/quic/build.info @@ -15,5 +15,6 @@ SOURCE[$LIBSSL]=quic_tls.c SOURCE[$LIBSSL]=quic_thread_assist.c SOURCE[$LIBSSL]=quic_trace.c SOURCE[$LIBSSL]=quic_srtm.c quic_srt_gen.c -SOURCE[$LIBSSL]=quic_lcidm.c +SOURCE[$LIBSSL]=quic_lcidm.c quic_rcidm.c SOURCE[$LIBSSL]=quic_types.c +SOURCE[$LIBSSL]=quic_lcidm.c diff --git a/ssl/quic/quic_rcidm.c b/ssl/quic/quic_rcidm.c new file mode 100644 index 0000000000000..b95936d9a7994 --- /dev/null +++ b/ssl/quic/quic_rcidm.c @@ -0,0 +1,619 @@ +/* + * 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 "internal/quic_rcidm.h" +#include "internal/priority_queue.h" +#include "internal/list.h" +#include "internal/common.h" + +/* + * QUIC Remote Connection ID Manager + * ================================= + * + * We can receive an arbitrary number of RCIDs via NCID frames. Periodically, we + * may desire (for example for anti-connection fingerprinting reasons, etc.) + * to switch to a new RCID according to some arbitrary policy such as the number + * of packets we have sent. + * + * When we do this we should move to the next RCID in the sequence of received + * RCIDs ordered by sequence number. For example, if a peer sends us three NCID + * frames with sequence numbers 10, 11, 12, we should seek to consume these + * RCIDs in order. + * + * However, due to the possibility of packet reordering in the network, NCID + * frames might be received out of order. Thus if a peer sends us NCID frames + * with sequence numbers 12, 10, 11, we should still consume the RCID with + * sequence number 10 before consuming the RCIDs with sequence numbers 11 or 12. + * + * We use a priority queue for this purpose. + */ +static void rcidm_update(QUIC_RCIDM *rcidm); +static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm, + const QUIC_CONN_ID *rcid); + +#define PACKETS_PER_RCID 1000 + +#define INITIAL_SEQ_NUM 0 +#define PREF_ADDR_SEQ_NUM 1 + +/* + * RCID + * ==== + * + * The RCID structure is used to track RCIDs which have sequence numbers (i.e., + * INITIAL, PREF_ADDR and NCID type RCIDs). The RCIDs without sequence numbers + * (Initial ODCIDs and Retry ODCIDs), hereafter referred to as unnumbered RCIDs, + * can logically be viewed as their own type of RCID but are tracked separately + * as singletons without needing a discrete structure. + * + * At any given time an RCID object is in one of these states: + * + * + * (start) + * | + * [add] + * | + * _____v_____ ___________ ____________ + * | | | | | | + * | PENDING | --[select]--> | CURRENT | --[retire]--> | RETIRING | + * |___________| |___________| |____________| + * | + * [pop] + * | + * v + * (fin) + * + * The transition through the states is monotonic and irreversible. + * The RCID object is freed when it is popped. + * + * PENDING + * Invariants: + * rcid->state == RCID_STATE_PENDING; + * rcid->pq_idx != SIZE_MAX (debug assert only); + * the RCID is not the current RCID, rcidm->cur_rcid != rcid; + * the RCID is in the priority queue; + * the RCID is not in the retiring_list. + * + * CURRENT + * Invariants: + * rcid->state == RCID_STATE_CUR; + * rcid->pq_idx == SIZE_MAX (debug assert only); + * the RCID is the current RCID, rcidm->cur_rcid == rcid; + * the RCID is not in the priority queue; + * the RCID is not in the retiring_list. + * + * RETIRE + * Invariants: + * rcid->state == RCID_STATE_RETIRE; + * rcid->pq_idx == SIZE_MAX (debug assert only); + * the RCID is not the current RCID, rcidm->cur_rcid != rcid; + * the RCID is not in the priority queue; + * the RCID is not in the retiring_list. + * + * Invariant: At most one RCID object is in the CURRENT state at any one time. + * + * (If no RCID object is in the CURRENT state, this means either + * an unnumbered RCID is being used as the preferred RCID + * or we currently have no preferred RCID.) + */ +enum { + RCID_STATE_PENDING, + RCID_STATE_CUR, + RCID_STATE_RETIRING, +}; + +enum { + RCID_TYPE_INITIAL, /* CID is from an peer INITIAL packet (seq 0) */ + RCID_TYPE_PREF_ADDR, /* CID is from a preferred_address TPARAM (seq 1) */ + RCID_TYPE_NCID, /* CID is from a NCID frame */ + /* + * INITIAL_ODCID and RETRY_ODCID also conceptually exist but are tracked + * separately. + */ +}; + +typedef struct rcid_st { + OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff retire == 1 */ + + QUIC_CONN_ID cid; /* The actual CID string for this RCID */ + uint64_t seq_num; + size_t pq_idx; /* Index of entry into priority queue */ + unsigned int state : 2; /* RCID_STATE_* */ + unsigned int type : 2; /* RCID_TYPE_* */ +} RCID; + +DEFINE_PRIORITY_QUEUE_OF(RCID); +DEFINE_LIST_OF(retiring, RCID); + +/* + * RCID Manager + * ============ + * + * The following "business logic" invariants also apply to the RCIDM + * as a whole: + * + * Invariant: An RCID of INITIAL type has a sequence number of 0. + * Invariant: An RCID of PREF_ADDR type has a sequence number of 1. + * + * Invariant: There is never more than one Initial ODCID + * added throughout the lifetime of an RCIDM. + * Invariant: There is never more than one Retry ODCID + * added throughout the lifetime of an RCIDM. + * Invariant: There is never more than one INITIAL RCID created + * throughout the lifetime of an RCIDM. + * Invariant: There is never more than one PREF_ADDR RCID created + * throughout the lifetime of an RCIDM. + * Invariant: No INITIAL or PREF_ADDR RCID may be added after + * the handshake is completed. + * + */ +struct quic_rcidm_st { + /* + * The current RCID we prefer to use (value undefined if + * !have_preferred_rcid). + */ + QUIC_CONN_ID preferred_rcid; + + /* + * These are initialized if the corresponding added_ flags are set. + */ + QUIC_CONN_ID initial_odcid, retry_odcid; + + /* + * Total number of packets sent since we last made a packet count-based RCID + * update decision. + */ + uint64_t packets_sent; + + /* Number of post-handshake RCID changes we have performed. */ + uint64_t num_changes; + + /* + * The Retire Prior To watermark value; max(retire_prior_to) of all received + * NCID frames. + */ + uint64_t retire_prior_to; + + /* (SORT BY seq_num ASC) -> (RCID *) */ + PRIORITY_QUEUE_OF(RCID) *rcids; + + /* + * Current RCID we are using. This may differ from the first item in the + * priority queue if we received NCID frames out of order. For example if we + * get seq 5, switch to it immediately, then get seq 4, we want to keep + * using seq 5 until we decide to roll again rather than immediately switch + * to seq 4. Never points to an object on the retiring_list. + */ + RCID *cur_rcid; + + /* + * When a RCID becomes pending-retirement, it is moved to the retiring_list, + * then freed when it is popped from the retired queue. We use a list for + * this rather than a priority queue as the order in which items are freed + * does not matter. We always append to the tail of the list in order to + * maintain the guarantee that the head (if present) only changes when a + * caller calls pop(). + */ + OSSL_LIST(retiring) retiring_list; + + /* preferred_rcid has been changed? */ + unsigned int preferred_rcid_changed : 1; + + /* Do we have any RCID we can use currently? */ + unsigned int have_preferred_rcid : 1; + + /* QUIC handshake has been completed? */ + unsigned int handshake_complete : 1; + + /* odcid was set (not necessarily still valid as a RCID)? */ + unsigned int added_initial_odcid : 1; + /* retry_odcid was set (not necessarily still valid as a RCID?) */ + unsigned int added_retry_odcid : 1; + /* An initial RCID was added as an RCID structure? */ + unsigned int added_initial_rcid : 1; + /* Has a RCID roll been manually requested? */ + unsigned int roll_requested : 1; +}; + +/* Check invariants of an RCID */ +static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid) +{ + assert(rcid->state == RCID_STATE_PENDING + || rcid->state == RCID_STATE_CUR + || rcid->state == RCID_STATE_RETIRING); + assert((rcid->state == RCID_STATE_PENDING) + == (rcid->pq_idx != SIZE_MAX)); + assert((rcid->state == RCID_STATE_CUR) + == (rcidm->cur_rcid == rcid)); + assert((ossl_list_retiring_next(rcid) != NULL + || ossl_list_retiring_prev(rcid) != NULL + || ossl_list_retiring_head(&rcidm->retiring_list) == rcid) + == (rcid->state == RCID_STATE_RETIRING)); + assert(rcid->type != RCID_TYPE_INITIAL || rcid->seq_num == 0); + assert(rcid->type != RCID_TYPE_PREF_ADDR || rcid->seq_num == 1); + assert(rcid->seq_num <= OSSL_QUIC_VLINT_MAX); + assert(rcid->cid.id_len > 0 && rcid->cid.id_len <= QUIC_MAX_CONN_ID_LEN); + assert(rcid->seq_num >= rcidm->retire_prior_to + || rcid->state == RCID_STATE_RETIRING); + assert(rcidm->num_changes == 0 || rcidm->handshake_complete); +} + +static int rcid_cmp(const RCID *a, const RCID *b) +{ + if (a->seq_num < b->seq_num) + return -1; + if (a->seq_num > b->seq_num) + return 1; + return 0; +} + +QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid) +{ + QUIC_RCIDM *rcidm; + + if ((rcidm = OPENSSL_zalloc(sizeof(*rcidm))) == NULL) + return NULL; + + if ((rcidm->rcids = ossl_pqueue_RCID_new(rcid_cmp)) == NULL) { + OPENSSL_free(rcidm); + return NULL; + } + + if (initial_odcid != NULL) { + rcidm->initial_odcid = *initial_odcid; + rcidm->added_initial_odcid = 1; + } + + rcidm_update(rcidm); + return rcidm; +} + +void ossl_quic_rcidm_free(QUIC_RCIDM *rcidm) +{ + RCID *rcid, *rnext; + + if (rcidm == NULL) + return; + + OPENSSL_free(rcidm->cur_rcid); + while ((rcid = ossl_pqueue_RCID_pop(rcidm->rcids)) != NULL) + OPENSSL_free(rcid); + + LIST_FOREACH_DELSAFE(rcid, rnext, retiring, &rcidm->retiring_list) + OPENSSL_free(rcid); + + ossl_pqueue_RCID_free(rcidm->rcids); + OPENSSL_free(rcidm); +} + +static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm, + const QUIC_CONN_ID *rcid) +{ + if (rcid == NULL) { + rcidm->preferred_rcid_changed = 1; + rcidm->have_preferred_rcid = 0; + return; + } + + if (ossl_quic_conn_id_eq(&rcidm->preferred_rcid, rcid)) + return; + + rcidm->preferred_rcid = *rcid; + rcidm->preferred_rcid_changed = 1; + rcidm->have_preferred_rcid = 1; +} + +/* + * RCID Lifecycle Management + * ========================= + */ +static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num, + const QUIC_CONN_ID *cid, + unsigned int type) +{ + RCID *rcid; + + if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL) + return NULL; + + rcid->seq_num = seq_num; + rcid->cid = *cid; + rcid->type = type; + rcid->state = RCID_STATE_PENDING; + + if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) { + OPENSSL_free(rcid); + return NULL; + } + + rcidm_check_rcid(rcidm, rcid); + return rcid; +} + +static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid, + unsigned int state) +{ + unsigned int old_state = rcid->state; + + assert(state >= old_state && state <= RCID_STATE_RETIRING); + rcidm_check_rcid(rcidm, rcid); + if (state == old_state) + return; + + if (rcidm->cur_rcid != NULL && state == RCID_STATE_CUR) { + rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING); + assert(rcidm->cur_rcid == NULL); + } + + if (old_state == RCID_STATE_PENDING) { + ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx); + rcid->pq_idx = SIZE_MAX; + } + + rcid->state = state; + + if (state == RCID_STATE_CUR) { + rcidm->cur_rcid = rcid; + } else if (state == RCID_STATE_RETIRING) { + if (old_state == RCID_STATE_CUR) + rcidm->cur_rcid = NULL; + + ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid); + } + + rcidm_check_rcid(rcidm, rcid); +} + +static void rcidm_free_rcid(QUIC_RCIDM *rcidm, RCID *rcid) +{ + if (rcid == NULL) + return; + + rcidm_check_rcid(rcidm, rcid); + + switch (rcid->state) { + case RCID_STATE_PENDING: + ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx); + break; + case RCID_STATE_CUR: + rcidm->cur_rcid = NULL; + break; + case RCID_STATE_RETIRING: + ossl_list_retiring_remove(&rcidm->retiring_list, rcid); + break; + default: + assert(0); + break; + } + + OPENSSL_free(rcid); +} + +static void rcidm_handle_retire_prior_to(QUIC_RCIDM *rcidm, + uint64_t retire_prior_to) +{ + RCID *rcid; + + if (retire_prior_to <= rcidm->retire_prior_to) + return; + + rcidm->retire_prior_to = retire_prior_to; + + /* + * Any RCIDs needing retirement will be at the start of the priority queue, + * so just stop once we see a higher sequence number exceeding the + * threshold. + */ + while ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL + && rcid->seq_num < retire_prior_to) + rcidm_transition_rcid(rcidm, rcid, RCID_STATE_RETIRING); +} + +/* + * Decision Logic + * ============== + */ + +static void rcidm_roll(QUIC_RCIDM *rcidm) +{ + RCID *rcid; + + if (ossl_pqueue_RCID_num(rcidm->rcids) < 1) + return; + + rcid = ossl_pqueue_RCID_peek(rcidm->rcids); + rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR); + + ++rcidm->num_changes; + rcidm->roll_requested = 0; + + if (rcidm->packets_sent >= PACKETS_PER_RCID) + rcidm->packets_sent %= PACKETS_PER_RCID; + else + rcidm->packets_sent = 0; +} + +static void rcidm_update(QUIC_RCIDM *rcidm) +{ + /* Prefer use of any current numbered RCID we have, if possible. */ + if (rcidm->cur_rcid != NULL) { + rcidm_check_rcid(rcidm, rcidm->cur_rcid); + rcidm_set_preferred_rcid(rcidm, &rcidm->cur_rcid->cid); + return; + } + + /* + * If there are no RCIDs from NCID frames we can use, go through the various + * kinds of bootstrapping RCIDs we can use in order of priority. + */ + if (rcidm->added_retry_odcid) { + rcidm_set_preferred_rcid(rcidm, &rcidm->retry_odcid); + return; + } + + if (rcidm->added_initial_odcid && !rcidm->handshake_complete) { + rcidm_set_preferred_rcid(rcidm, &rcidm->initial_odcid); + return; + } + + /* We don't know of any usable RCIDs */ + rcidm_set_preferred_rcid(rcidm, NULL); +} + +static int rcidm_should_roll(QUIC_RCIDM *rcidm) +{ + /* + * Always switch as soon as possible if handshake completes; + * and every n packets after handshake completes or the last roll; and + * whenever manually requested. + */ + return rcidm->handshake_complete + && (rcidm->num_changes == 0 + || rcidm->packets_sent >= PACKETS_PER_RCID + || rcidm->roll_requested); +} + +static void rcidm_tick(QUIC_RCIDM *rcidm) +{ + if (rcidm_should_roll(rcidm)) + rcidm_roll(rcidm); + + rcidm_update(rcidm); +} + +/* + * Events + * ====== + */ +void ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM *rcidm) +{ + if (rcidm->handshake_complete) + return; + + rcidm->handshake_complete = 1; + rcidm_tick(rcidm); +} + +void ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM *rcidm, uint64_t num_packets) +{ + if (num_packets == 0) + return; + + rcidm->packets_sent += num_packets; + rcidm_tick(rcidm); +} + +void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm) +{ + rcidm->roll_requested = 1; + rcidm_tick(rcidm); +} + +/* + * Mutation Operations + * =================== + */ +int ossl_quic_rcidm_add_from_initial(QUIC_RCIDM *rcidm, + const QUIC_CONN_ID *rcid) +{ + RCID *rcid_obj; + + if (rcidm->added_initial_rcid || rcidm->handshake_complete) + return 0; + + rcid_obj = rcidm_create_rcid(rcidm, INITIAL_SEQ_NUM, + rcid, RCID_TYPE_INITIAL); + if (rcid_obj == NULL) + return 0; + + rcidm->added_initial_rcid = 1; + rcidm_tick(rcidm); + return 1; +} + +int ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM *rcidm, + const QUIC_CONN_ID *retry_odcid) +{ + if (rcidm->added_retry_odcid || rcidm->handshake_complete) + return 0; + + rcidm->retry_odcid = *retry_odcid; + rcidm->added_retry_odcid = 1; + rcidm_tick(rcidm); + return 1; +} + +int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm, + const OSSL_QUIC_FRAME_NEW_CONN_ID *ncid) +{ + RCID *rcid; + + rcidm_handle_retire_prior_to(rcidm, ncid->retire_prior_to); + + rcid = rcidm_create_rcid(rcidm, ncid->seq_num, &ncid->conn_id, RCID_TYPE_NCID); + if (rcid == NULL) + return 0; + + rcidm_tick(rcidm); + return 1; +} + +/* + * Queries + * ======= + */ + +static int rcidm_get_retire(QUIC_RCIDM *rcidm, uint64_t *seq_num, int peek) +{ + RCID *rcid = ossl_list_retiring_head(&rcidm->retiring_list); + + if (rcid == NULL) + return 0; + + if (seq_num != NULL) + *seq_num = rcid->seq_num; + + if (!peek) + rcidm_free_rcid(rcidm, rcid); + + return 1; +} + +int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcidm, + uint64_t *seq_num) +{ + return rcidm_get_retire(rcidm, seq_num, /*peek=*/0); +} + +int ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM *rcidm, + uint64_t *seq_num) +{ + return rcidm_get_retire(rcidm, seq_num, /*peek=*/1); +} + +int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm, + QUIC_CONN_ID *tx_dcid) +{ + if (!rcidm->have_preferred_rcid) + return 0; + + *tx_dcid = rcidm->preferred_rcid; + return 1; +} + +int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm, + int clear) +{ + int r = rcidm->preferred_rcid_changed; + + if (clear) + rcidm->preferred_rcid_changed = 0; + + return r; +} From d0bac943c99fa73ce0c6c879d269fc1cf42c16ad Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 7 Nov 2023 15:24:17 +0000 Subject: [PATCH 49/81] QUIC RCIDM: Add fuzzer Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- fuzz/build.info | 11 +- fuzz/quic-rcidm.c | 198 +++++++++++++++++++++++++ test/recipes/99-test_fuzz_quic_rcidm.t | 25 ++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 fuzz/quic-rcidm.c create mode 100644 test/recipes/99-test_fuzz_quic_rcidm.t diff --git a/fuzz/build.info b/fuzz/build.info index 3fc4345a89aca..5e024d4cd029d 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -30,7 +30,7 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] ENDIF IF[{- !$disabled{"quic"} -}] - PROGRAMS{noinst}=quic-client quic-srtm quic-lcidm + PROGRAMS{noinst}=quic-client quic-srtm quic-lcidm quic-rcidm ENDIF SOURCE[asn1]=asn1.c driver.c fuzz_rand.c @@ -105,6 +105,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] INCLUDE[quic-lcidm]=../include {- $ex_inc -} DEPEND[quic-lcidm]=../libcrypto.a ../libssl.a {- $ex_lib -} + SOURCE[quic-rcidm]=quic-rcidm.c driver.c fuzz_rand.c + INCLUDE[quic-rcidm]=../include {- $ex_inc -} + DEPEND[quic-rcidm]=../libcrypto.a ../libssl.a {- $ex_lib -} + SOURCE[server]=server.c driver.c fuzz_rand.c INCLUDE[server]=../include {- $ex_inc -} DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} @@ -137,6 +141,7 @@ IF[{- !$disabled{tests} -}] IF[{- !$disabled{"quic"} -}] PROGRAMS{noinst}=quic-client-test quic-srtm-test quic-lcidm-test + PROGRAMS{noinst}=quic-rcidm-test ENDIF SOURCE[asn1-test]=asn1.c test-corpus.c fuzz_rand.c @@ -212,6 +217,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[quic-lcidm-test]=../include DEPEND[quic-lcidm-test]=../libcrypto.a ../libssl.a + SOURCE[quic-rcidm-test]=quic-rcidm.c test-corpus.c fuzz_rand.c + INCLUDE[quic-rcidm-test]=../include + DEPEND[quic-rcidm-test]=../libcrypto.a ../libssl.a + 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-rcidm.c b/fuzz/quic-rcidm.c new file mode 100644 index 0000000000000..51919b8d70eb7 --- /dev/null +++ b/fuzz/quic-rcidm.c @@ -0,0 +1,198 @@ +/* + * 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 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 "fuzzer.h" +#include "internal/quic_rcidm.h" +#include "internal/packet.h" + +int FuzzerInitialize(int *argc, char ***argv) +{ + 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(); + return 1; +} + +/* + * Fuzzer input "protocol": + * Big endian + * Zero or more of: + * RESET_WITH_ODCID u8(0x00) u8(cidl):cid + * RESET_WITHOUT_ODCID u8(0x01) + * (free and reallocate) + * ADD_FROM_INITIAL u8(0x02) u8(cidl):cid + * ADD_FROM_SERVER_RETRY u8(0x03) u8(cidl):cid + * ADD_FROM_NCID u8(0x04) u64(seq_num) + * u64(retire_prior_to) u8(cidl):cid + * ON_HANDSHAKE_COMPLETE u8(0x05) + * ON_PACKET_SENT u8(0x06) u64(num_pkt) + * REQUEST_ROLL u8(0x07) + * POP_RETIRE_SEQ_NUM u8(0x08) + * PEEK_RETIRE_SEQ_NUM u8(0x09) + * GET_PREFERRED_TX_DCID u8(0x0A) + * GET_PREFERRED_TX_DCID_CHANGED u8(0x0B) u8(clear) + */ + +enum { + CMD_RESET_WITH_ODCID, + CMD_RESET_WITHOUT_ODCID, + CMD_ADD_FROM_INITIAL, + CMD_ADD_FROM_SERVER_RETRY, + CMD_ADD_FROM_NCID, + CMD_ON_HANDSHAKE_COMPLETE, + CMD_ON_PACKET_SENT, + CMD_REQUEST_ROLL, + CMD_POP_RETIRE_SEQ_NUM, + CMD_PEEK_RETIRE_SEQ_NUM, + CMD_GET_PREFERRED_TX_DCID, + CMD_GET_PREFERRED_TX_DCID_CHANGED +}; + +static int get_cid(PACKET *pkt, QUIC_CONN_ID *cid) +{ + unsigned int cidl; + + if (!PACKET_get_1(pkt, &cidl) + || cidl > QUIC_MAX_CONN_ID_LEN + || !PACKET_copy_bytes(pkt, cid->id, cidl)) + return 0; + + cid->id_len = (unsigned char)cidl; + return 1; +} + +int FuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + int rc = 0; + QUIC_RCIDM *rcidm = NULL; + PACKET pkt; + uint64_t seq_num_out, arg_num_pkt; + unsigned int cmd, arg_clear; + QUIC_CONN_ID arg_cid, cid_out; + OSSL_QUIC_FRAME_NEW_CONN_ID ncid_frame; + + if (!PACKET_buf_init(&pkt, buf, len)) + goto err; + + if ((rcidm = ossl_quic_rcidm_new(NULL)) == NULL) + goto err; + + while (PACKET_remaining(&pkt) > 0) { + if (!PACKET_get_1(&pkt, &cmd)) + goto err; + + switch (cmd) { + case CMD_RESET_WITH_ODCID: + if (!get_cid(&pkt, &arg_cid)) { + rc = -1; + goto err; + } + + ossl_quic_rcidm_free(rcidm); + + if ((rcidm = ossl_quic_rcidm_new(&arg_cid)) == NULL) + goto err; + + break; + + case CMD_RESET_WITHOUT_ODCID: + ossl_quic_rcidm_free(rcidm); + + if ((rcidm = ossl_quic_rcidm_new(NULL)) == NULL) + goto err; + + break; + + case CMD_ADD_FROM_INITIAL: + if (!get_cid(&pkt, &arg_cid)) { + rc = -1; + goto err; + } + + ossl_quic_rcidm_add_from_initial(rcidm, &arg_cid); + break; + + case CMD_ADD_FROM_SERVER_RETRY: + if (!get_cid(&pkt, &arg_cid)) { + rc = -1; + goto err; + } + + ossl_quic_rcidm_add_from_initial(rcidm, &arg_cid); + break; + + case CMD_ADD_FROM_NCID: + if (!PACKET_get_net_8(&pkt, &ncid_frame.seq_num) + || !PACKET_get_net_8(&pkt, &ncid_frame.retire_prior_to) + || !get_cid(&pkt, &ncid_frame.conn_id)) { + rc = -1; + goto err; + } + + ossl_quic_rcidm_add_from_ncid(rcidm, &ncid_frame); + break; + + case CMD_ON_HANDSHAKE_COMPLETE: + ossl_quic_rcidm_on_handshake_complete(rcidm); + break; + + case CMD_ON_PACKET_SENT: + if (!PACKET_get_net_8(&pkt, &arg_num_pkt)) { + rc = -1; + goto err; + } + + ossl_quic_rcidm_on_packet_sent(rcidm, arg_num_pkt); + break; + + case CMD_REQUEST_ROLL: + ossl_quic_rcidm_request_roll(rcidm); + break; + + case CMD_POP_RETIRE_SEQ_NUM: + ossl_quic_rcidm_pop_retire_seq_num(rcidm, &seq_num_out); + break; + + case CMD_PEEK_RETIRE_SEQ_NUM: + ossl_quic_rcidm_peek_retire_seq_num(rcidm, &seq_num_out); + break; + + case CMD_GET_PREFERRED_TX_DCID: + ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &cid_out); + break; + + case CMD_GET_PREFERRED_TX_DCID_CHANGED: + if (!PACKET_get_1(&pkt, &arg_clear)) { + rc = -1; + goto err; + } + + ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, arg_clear); + break; + + default: + rc = -1; + goto err; + } + } + +err: + ossl_quic_rcidm_free(rcidm); + return rc; +} + +void FuzzerCleanup(void) +{ + FuzzerClearRand(); +} diff --git a/test/recipes/99-test_fuzz_quic_rcidm.t b/test/recipes/99-test_fuzz_quic_rcidm.t new file mode 100644 index 0000000000000..ea33651beb0f0 --- /dev/null +++ b/test/recipes/99-test_fuzz_quic_rcidm.t @@ -0,0 +1,25 @@ +#!/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 strict; +use warnings; + +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test::Utils; + +my $fuzzer = "quic-rcidm"; +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')); + +fuzz_ok($fuzzer); From 3fe0899ab7c1c1727a9fe0d3981f658262283690 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 7 Nov 2023 15:24:46 +0000 Subject: [PATCH 50/81] QUIC RCIDM: Minor fixes Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- ssl/quic/quic_rcidm.c | 70 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/ssl/quic/quic_rcidm.c b/ssl/quic/quic_rcidm.c index b95936d9a7994..91391d6589a35 100644 --- a/ssl/quic/quic_rcidm.c +++ b/ssl/quic/quic_rcidm.c @@ -88,19 +88,24 @@ static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm, * the RCID is not in the priority queue; * the RCID is not in the retiring_list. * - * RETIRE + * RETIRING * Invariants: - * rcid->state == RCID_STATE_RETIRE; + * rcid->state == RCID_STATE_RETIRING; * rcid->pq_idx == SIZE_MAX (debug assert only); * the RCID is not the current RCID, rcidm->cur_rcid != rcid; * the RCID is not in the priority queue; - * the RCID is not in the retiring_list. + * the RCID is in the retiring_list. * * Invariant: At most one RCID object is in the CURRENT state at any one time. * * (If no RCID object is in the CURRENT state, this means either * an unnumbered RCID is being used as the preferred RCID * or we currently have no preferred RCID.) + * + * All of the above states can be considered substates of the 'ACTIVE' state + * for an RCID as specified in RFC 9000. A CID only ceases to be active + * when we send a RETIRE_CONN_ID frame, which is the responsibility of the + * user of the RCIDM and happens after the above state machine is terminated. */ enum { RCID_STATE_PENDING, @@ -221,6 +226,9 @@ struct quic_rcidm_st { unsigned int roll_requested : 1; }; +static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid, + unsigned int state); + /* Check invariants of an RCID */ static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid) { @@ -250,6 +258,10 @@ static int rcid_cmp(const RCID *a, const RCID *b) return -1; if (a->seq_num > b->seq_num) return 1; + if ((uintptr_t)a < (uintptr_t)b) + return -1; + if ((uintptr_t)a > (uintptr_t)b) + return 1; return 0; } @@ -319,17 +331,30 @@ static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num, { RCID *rcid; + if (cid->id_len < 1 || cid->id_len > QUIC_MAX_CONN_ID_LEN + || seq_num > OSSL_QUIC_VLINT_MAX) + return NULL; + if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL) return NULL; rcid->seq_num = seq_num; rcid->cid = *cid; rcid->type = type; - rcid->state = RCID_STATE_PENDING; - if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) { - OPENSSL_free(rcid); - return NULL; + if (rcid->seq_num >= rcidm->retire_prior_to) { + rcid->state = RCID_STATE_PENDING; + + if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) { + assert(0); + OPENSSL_free(rcid); + return NULL; + } + } else { + /* RCID is immediately retired upon creation. */ + rcid->state = RCID_STATE_RETIRING; + rcid->pq_idx = SIZE_MAX; + ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid); } rcidm_check_rcid(rcidm, rcid); @@ -403,16 +428,22 @@ static void rcidm_handle_retire_prior_to(QUIC_RCIDM *rcidm, if (retire_prior_to <= rcidm->retire_prior_to) return; - rcidm->retire_prior_to = retire_prior_to; + /* + * Retire the current RCID (if any) if it is affected. + */ + if (rcidm->cur_rcid != NULL && rcidm->cur_rcid->seq_num < retire_prior_to) + rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING); /* - * Any RCIDs needing retirement will be at the start of the priority queue, - * so just stop once we see a higher sequence number exceeding the + * Any other RCIDs needing retirement will be at the start of the priority + * queue, so just stop once we see a higher sequence number exceeding the * threshold. */ while ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL && rcid->seq_num < retire_prior_to) rcidm_transition_rcid(rcidm, rcid, RCID_STATE_RETIRING); + + rcidm->retire_prior_to = retire_prior_to; } /* @@ -424,10 +455,9 @@ static void rcidm_roll(QUIC_RCIDM *rcidm) { RCID *rcid; - if (ossl_pqueue_RCID_num(rcidm->rcids) < 1) + if ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) == NULL) return; - rcid = ossl_pqueue_RCID_peek(rcidm->rcids); rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR); ++rcidm->num_changes; @@ -441,6 +471,17 @@ static void rcidm_roll(QUIC_RCIDM *rcidm) static void rcidm_update(QUIC_RCIDM *rcidm) { + RCID *rcid; + + /* + * If we have no current numbered RCID but have one or more pending, use it. + */ + if (rcidm->cur_rcid == NULL + && (rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL) { + rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR); + assert(rcidm->cur_rcid != NULL); + } + /* Prefer use of any current numbered RCID we have, if possible. */ if (rcidm->cur_rcid != NULL) { rcidm_check_rcid(rcidm, rcidm->cur_rcid); @@ -554,12 +595,11 @@ int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm, { RCID *rcid; - rcidm_handle_retire_prior_to(rcidm, ncid->retire_prior_to); - rcid = rcidm_create_rcid(rcidm, ncid->seq_num, &ncid->conn_id, RCID_TYPE_NCID); if (rcid == NULL) return 0; + rcidm_handle_retire_prior_to(rcidm, ncid->retire_prior_to); rcidm_tick(rcidm); return 1; } @@ -617,3 +657,5 @@ int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm, return r; } + +// TODO expose counters for enforcement From 044fd04cb4005dbb08c556dcf1e87fda9b7a45ba Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 7 Nov 2023 15:24:54 +0000 Subject: [PATCH 51/81] QUIC SRTM: Fixes for clang Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- ssl/quic/quic_srtm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssl/quic/quic_srtm.c b/ssl/quic/quic_srtm.c index faa667253e6f4..dcb98ea60e02c 100644 --- a/ssl/quic/quic_srtm.c +++ b/ssl/quic/quic_srtm.c @@ -478,8 +478,8 @@ static void check_mark(SRTM_ITEM *item, void *arg) { struct check_args *arg_ = arg; uint32_t token = arg_->token; - uint64_t prev_seq_num; - void *prev_opaque; + uint64_t prev_seq_num = 0; + void *prev_opaque = NULL; int have_prev = 0; assert(item != NULL); From 9575b21851e3dcb53d713dc4051a989c856f53b1 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 7 Nov 2023 15:31:30 +0000 Subject: [PATCH 52/81] QUIC RCIDM: Add counters to support RCID count enforcement Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- include/internal/quic_rcidm.h | 13 +++++++++++++ ssl/quic/quic_rcidm.c | 20 +++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/internal/quic_rcidm.h b/include/internal/quic_rcidm.h index cd90d0948105f..4837fed480cf3 100644 --- a/include/internal/quic_rcidm.h +++ b/include/internal/quic_rcidm.h @@ -166,6 +166,19 @@ int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm, int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm, int clear); +/* + * Returns the number of active numbered RCIDs we have. Note that this includes + * RCIDs on the retir*ing* queue accessed via + * ossl_quic_rcidm_pop_retire_seq_num() as these are still active until actually + * retired. + */ +size_t ossl_quic_rcidm_get_num_active(const QUIC_RCIDM *rcidm); + +/* + * Returns the number of retir*ing* numbered RCIDs we have. + */ +size_t ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM *rcidm); + # endif #endif diff --git a/ssl/quic/quic_rcidm.c b/ssl/quic/quic_rcidm.c index 91391d6589a35..05cfa054c6acd 100644 --- a/ssl/quic/quic_rcidm.c +++ b/ssl/quic/quic_rcidm.c @@ -207,6 +207,9 @@ struct quic_rcidm_st { */ OSSL_LIST(retiring) retiring_list; + /* Number of entries on the retiring_list. */ + size_t num_retiring; + /* preferred_rcid has been changed? */ unsigned int preferred_rcid_changed : 1; @@ -250,6 +253,8 @@ static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid) assert(rcid->seq_num >= rcidm->retire_prior_to || rcid->state == RCID_STATE_RETIRING); assert(rcidm->num_changes == 0 || rcidm->handshake_complete); + assert(rcid->state != RCID_STATE_RETIRING || rcidm->num_retiring > 0); + assert(rcidm->num_retiring < SIZE_MAX / 2); } static int rcid_cmp(const RCID *a, const RCID *b) @@ -355,6 +360,7 @@ static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num, rcid->state = RCID_STATE_RETIRING; rcid->pq_idx = SIZE_MAX; ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid); + ++rcidm->num_retiring; } rcidm_check_rcid(rcidm, rcid); @@ -390,6 +396,7 @@ static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid, rcidm->cur_rcid = NULL; ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid); + ++rcidm->num_retiring; } rcidm_check_rcid(rcidm, rcid); @@ -411,6 +418,7 @@ static void rcidm_free_rcid(QUIC_RCIDM *rcidm, RCID *rcid) break; case RCID_STATE_RETIRING: ossl_list_retiring_remove(&rcidm->retiring_list, rcid); + --rcidm->num_retiring; break; default: assert(0); @@ -658,4 +666,14 @@ int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm, return r; } -// TODO expose counters for enforcement +size_t ossl_quic_rcidm_get_num_active(const QUIC_RCIDM *rcidm) +{ + return ossl_pqueue_RCID_num(rcidm->rcids) + + (rcidm->cur_rcid != NULL ? 1 : 0) + + ossl_quic_rcidm_get_num_retiring(rcidm); +} + +size_t ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM *rcidm) +{ + return rcidm->num_retiring; +} From 433ef94187b096a4e108845bb64007371a2341a0 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 7 Nov 2023 15:57:05 +0000 Subject: [PATCH 53/81] QUIC RCIDM: Add test Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- test/build.info | 6 +- test/quic_rcidm_test.c | 127 ++++++++++++++++++++++++++++++ test/recipes/70-test_quic_rcidm.t | 19 +++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 test/quic_rcidm_test.c create mode 100644 test/recipes/70-test_quic_rcidm.t diff --git a/test/build.info b/test/build.info index 88620b86b3294..7e1ce28522025 100644 --- a/test/build.info +++ b/test/build.info @@ -344,6 +344,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[quic_lcidm_test]=../include ../apps/include DEPEND[quic_lcidm_test]=../libcrypto.a ../libssl.a libtestutil.a + SOURCE[quic_rcidm_test]=quic_rcidm_test.c + INCLUDE[quic_rcidm_test]=../include ../apps/include + DEPEND[quic_rcidm_test]=../libcrypto.a ../libssl.a libtestutil.a + SOURCE[quic_fifd_test]=quic_fifd_test.c cc_dummy.c INCLUDE[quic_fifd_test]=../include ../apps/include DEPEND[quic_fifd_test]=../libcrypto.a ../libssl.a libtestutil.a @@ -1160,7 +1164,7 @@ ENDIF IF[{- !$disabled{'quic'} -}] PROGRAMS{noinst}=quic_wire_test quic_ackm_test quic_record_test PROGRAMS{noinst}=quic_fc_test quic_stream_test quic_cfq_test quic_txpim_test - PROGRAMS{noinst}=quic_srtm_test quic_lcidm_test + PROGRAMS{noinst}=quic_srtm_test quic_lcidm_test quic_rcidm_test PROGRAMS{noinst}=quic_fifd_test quic_txp_test quic_tserver_test PROGRAMS{noinst}=quic_client_test quic_cc_test quic_multistream_test ENDIF diff --git a/test/quic_rcidm_test.c b/test/quic_rcidm_test.c new file mode 100644 index 0000000000000..3e841bed569ab --- /dev/null +++ b/test/quic_rcidm_test.c @@ -0,0 +1,127 @@ +/* + * 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 "internal/quic_rcidm.h" +#include "testutil.h" + +static const QUIC_CONN_ID cid8_1 = { 8, { 1 } }; +static const QUIC_CONN_ID cid8_2 = { 8, { 2 } }; +static const QUIC_CONN_ID cid8_3 = { 8, { 3 } }; +static const QUIC_CONN_ID cid8_4 = { 8, { 4 } }; +static const QUIC_CONN_ID cid8_5 = { 8, { 5 } }; + +static int test_rcidm(int idx) +{ + int testresult = 0; + QUIC_RCIDM *rcidm; + OSSL_QUIC_FRAME_NEW_CONN_ID ncid_frame_1 = {0}, ncid_frame_2 = {0}; + QUIC_CONN_ID dcid_out; + const QUIC_CONN_ID *odcid = NULL; + uint64_t seq_num_out; + + ncid_frame_1.seq_num = 2; + ncid_frame_1.conn_id.id_len = 8; + ncid_frame_1.conn_id.id[0] = 3; + + ncid_frame_2.seq_num = 3; + ncid_frame_2.conn_id.id_len = 8; + ncid_frame_2.conn_id.id[0] = 4; + + odcid = ((idx == 2) ? NULL : &cid8_1); + if (!TEST_ptr(rcidm = ossl_quic_rcidm_new(odcid))) + goto err; + + if (idx != 2) { + if (/* ODCID not counted */ + !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 0)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_1)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_active(rcidm), 0)) + goto err; + } else { + if (!TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_active(rcidm), 0)) + goto err; + } + + if (idx == 1) { + if (!TEST_true(ossl_quic_rcidm_add_from_server_retry(rcidm, &cid8_5)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 0)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_5)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_active(rcidm), 0)) + goto err; + } + + if (!TEST_true(ossl_quic_rcidm_add_from_initial(rcidm, &cid8_2)) + /* Initial SCID (seq=0) is counted */ + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_active(rcidm), 1) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 0)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_2)) + + || !TEST_true(ossl_quic_rcidm_add_from_ncid(rcidm, &ncid_frame_1)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_active(rcidm), 2) + /* Not changed over yet - handshake not confirmed */ + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 0)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_2)) + + || !TEST_true(ossl_quic_rcidm_add_from_ncid(rcidm, &ncid_frame_2)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_active(rcidm), 3) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_retiring(rcidm), 0) + || !TEST_false(ossl_quic_rcidm_pop_retire_seq_num(rcidm, &seq_num_out)) + /* Not changed over yet - handshake not confirmed */ + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 0)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_2))) + goto err; + + ossl_quic_rcidm_on_handshake_complete(rcidm); + + if (!TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_3)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_retiring(rcidm), 1) + || !TEST_true(ossl_quic_rcidm_peek_retire_seq_num(rcidm, &seq_num_out)) + || !TEST_uint64_t_eq(seq_num_out, 0)) + goto err; + + ossl_quic_rcidm_request_roll(rcidm); + + if (!TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_false(ossl_quic_rcidm_get_preferred_tx_dcid_changed(rcidm, 1)) + || !TEST_true(ossl_quic_rcidm_get_preferred_tx_dcid(rcidm, &dcid_out)) + || !TEST_true(ossl_quic_conn_id_eq(&dcid_out, &cid8_4)) + || !TEST_size_t_eq(ossl_quic_rcidm_get_num_retiring(rcidm), 2) + || !TEST_true(ossl_quic_rcidm_peek_retire_seq_num(rcidm, &seq_num_out)) + || !TEST_uint64_t_eq(seq_num_out, 0) + || !TEST_true(ossl_quic_rcidm_pop_retire_seq_num(rcidm, &seq_num_out)) + || !TEST_uint64_t_eq(seq_num_out, 0) + || !TEST_true(ossl_quic_rcidm_pop_retire_seq_num(rcidm, &seq_num_out)) + || !TEST_uint64_t_eq(seq_num_out, 2)) + goto err; + + testresult = 1; +err: + ossl_quic_rcidm_free(rcidm); + return testresult; +} + +int setup_tests(void) +{ + ADD_ALL_TESTS(test_rcidm, 3); + return 1; +} diff --git a/test/recipes/70-test_quic_rcidm.t b/test/recipes/70-test_quic_rcidm.t new file mode 100644 index 0000000000000..a00f381eb6fad --- /dev/null +++ b/test/recipes/70-test_quic_rcidm.t @@ -0,0 +1,19 @@ +#! /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; +use OpenSSL::Test::Utils; + +setup("test_quic_rcidm"); + +plan skip_all => "QUIC protocol is not supported by this OpenSSL build" + if disabled('quic'); + +plan tests => 1; + +ok(run(test(["quic_rcidm_test"]))); From 3ba9345eb9ccae3bf7204f3f6418c61e9aebe31d Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 19 Dec 2023 16:20:31 +0000 Subject: [PATCH 54/81] QUIC RCIDM: Fix ANSI compliance Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- ssl/quic/quic_rcidm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssl/quic/quic_rcidm.c b/ssl/quic/quic_rcidm.c index 05cfa054c6acd..c2fd65960975a 100644 --- a/ssl/quic/quic_rcidm.c +++ b/ssl/quic/quic_rcidm.c @@ -110,13 +110,13 @@ static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm, enum { RCID_STATE_PENDING, RCID_STATE_CUR, - RCID_STATE_RETIRING, + RCID_STATE_RETIRING }; enum { RCID_TYPE_INITIAL, /* CID is from an peer INITIAL packet (seq 0) */ RCID_TYPE_PREF_ADDR, /* CID is from a preferred_address TPARAM (seq 1) */ - RCID_TYPE_NCID, /* CID is from a NCID frame */ + RCID_TYPE_NCID /* CID is from a NCID frame */ /* * INITIAL_ODCID and RETRY_ODCID also conceptually exist but are tracked * separately. From 8e1593e647621c796cacba5bfd07d898a861fd12 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 19 Dec 2023 16:22:02 +0000 Subject: [PATCH 55/81] QUIC RCIDM: Update fuzz corpora Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- fuzz/corpora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/corpora b/fuzz/corpora index 8663e2d71fa93..445637df5d4e5 160000 --- a/fuzz/corpora +++ b/fuzz/corpora @@ -1 +1 @@ -Subproject commit 8663e2d71fa934e7846fa4c5fb6de7cb3afc53fd +Subproject commit 445637df5d4e556c076bf4e348c5b69159850c24 From ad08c814d84a203595985465933799f95fa08075 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Thu, 21 Dec 2023 09:40:58 +0000 Subject: [PATCH 56/81] Update fuzz corpora Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- fuzz/corpora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/corpora b/fuzz/corpora index 445637df5d4e5..de68c9ed187c5 160000 --- a/fuzz/corpora +++ b/fuzz/corpora @@ -1 +1 @@ -Subproject commit 445637df5d4e556c076bf4e348c5b69159850c24 +Subproject commit de68c9ed187c5c9b57c663e9ef5f0d66a2736b1c From 9eabb30ab4491bdcf49c5bfeef659ca846da5160 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Fri, 22 Dec 2023 12:18:19 +0000 Subject: [PATCH 57/81] QUIC RCIDM: Minor updates Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23022) --- doc/designs/quic-design/glossary.md | 15 ++++++++++- fuzz/quic-rcidm.c | 2 +- include/internal/quic_rcidm.h | 17 +++++++------ ssl/quic/quic_rcidm.c | 39 ++++++++++++++++++----------- test/quic_rcidm_test.c | 5 ++++ 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/doc/designs/quic-design/glossary.md b/doc/designs/quic-design/glossary.md index 3993c6f8453ba..1cf0f06cddda4 100644 --- a/doc/designs/quic-design/glossary.md +++ b/doc/designs/quic-design/glossary.md @@ -128,6 +128,12 @@ in which API calls can be made on different threads. **MSST:** Multi-stream single-thread. Refers to a type of multi-stream QUIC usage in which API calls must not be made concurrently. +**NCID:** New Connection ID. Refers to a QUIC `NEW_CONNECTION_ID` frame. + +**Numbered CID:** Refers to a Connection ID which has a sequence number assigned +to it. All CIDs other than Initial ODCIDs and Retry ODCIDs have a sequence +number assigned. See also Unnumbered CID. + **ODCID:** Original Destination CID. This is the DCID found in the first Initial packet sent by a client, and is used to generate the secrets for encrypting Initial packets. It is only used temporarily. @@ -195,7 +201,8 @@ an API object. As such, a `QUIC_CONNECTION` is to a `QUIC_CHANNEL` what a `QUIC_XSO` is to a `QUIC_STREAM`. **RCID:** Remote CID. Refers to a CID which has been provided to us by a peer -and which we can place in the DCID field of an outgoing packet. See also LCID. +and which we can place in the DCID field of an outgoing packet. See also LCID, +Unnumbered CID and Numbered CID. **RCIDM:** Remote CID Manager. Tracks RCIDs which have been provided to us by a peer. See also LCIDM. @@ -284,6 +291,12 @@ to a *send stream buffer*, and that data is eventually TX'd by the TXP and QTX.) **Uni:** Abbreviation of unidirectional, referring to a QUIC unidirectional stream. +**Unnumbered CID:** Refers to a CID which does not have a sequence number +associated with it and therefore cannot be referred to by a `NEW_CONNECTION_ID` +or `RETIRE_CONNECTION_ID` frame's sequence number fields. The only unnumbered +CIDs are Initial ODCIDs and Retry ODCIDs. These CIDs are exceptionally retired +automatically during handshake confirmation. See also Numbered CID. + **URXE:** Unprocessed RX entry. Structure containing yet-undecrypted received datagrams pending processing. Stored in a queue known as the URXL. Ownership of URXEs is shared between DEMUX and QRX. diff --git a/fuzz/quic-rcidm.c b/fuzz/quic-rcidm.c index 51919b8d70eb7..825fe0c2fdf8a 100644 --- a/fuzz/quic-rcidm.c +++ b/fuzz/quic-rcidm.c @@ -129,7 +129,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) goto err; } - ossl_quic_rcidm_add_from_initial(rcidm, &arg_cid); + ossl_quic_rcidm_add_from_server_retry(rcidm, &arg_cid); break; case CMD_ADD_FROM_NCID: diff --git a/include/internal/quic_rcidm.h b/include/internal/quic_rcidm.h index 4837fed480cf3..8eeaaf550e533 100644 --- a/include/internal/quic_rcidm.h +++ b/include/internal/quic_rcidm.h @@ -22,10 +22,10 @@ * QUIC Remote Connection ID Manager * ================================= * - * This manages connection IDs for the TX side, which is to say that it tracks - * remote CIDs (RCIDs) which a peer has issued to us and which we can use as the - * DCID of packets we transmit. It is entirely separate from the LCIDM, which - * handles routing received packets by their DCIDs. + * This manages connection IDs for the TX side. The RCIDM tracks remote CIDs + * (RCIDs) which a peer has issued to us and which we can use as the DCID of + * packets we transmit. It is entirely separate from the LCIDM, which handles + * routing received packets by their DCIDs. * * RCIDs fall into four categories: * @@ -42,8 +42,8 @@ typedef struct quic_rcidm_st QUIC_RCIDM; /* * Creates a new RCIDM. Returns NULL on failure. * - * For a client, initial_rcid is the client's Initial ODCID. - * For a server, initial_rcid is NULL. + * For a client, initial_odcid is the client's Initial ODCID. + * For a server, initial_odcid is NULL. */ QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid); @@ -135,12 +135,13 @@ void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm); * packets using the RCID may still be in flight. The caller must determine an * appropriate delay using knowledge of network conditions (RTT, etc.) which is * outside the scope of the RCIDM. The caller is responsible for implementing - * this delay. + * this delay based on the last time a packet was transmitted using the RCID + * being retired. */ int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcid, uint64_t *seq_num); /* - * Like ossl_quic_rcidm_pop_retire_seek_num, but does not pop the item from the + * Like ossl_quic_rcidm_pop_retire_seq_num, but does not pop the item from the * queue. If this call succeeds, the next call to * ossl_quic_rcidm_pop_retire_seq_num is guaranteed to output the same sequence * number. diff --git a/ssl/quic/quic_rcidm.c b/ssl/quic/quic_rcidm.c index c2fd65960975a..90a4b2c2aeba6 100644 --- a/ssl/quic/quic_rcidm.c +++ b/ssl/quic/quic_rcidm.c @@ -37,7 +37,7 @@ static void rcidm_update(QUIC_RCIDM *rcidm); static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm, const QUIC_CONN_ID *rcid); -#define PACKETS_PER_RCID 1000 +#define PACKETS_PER_RCID 10000 #define INITIAL_SEQ_NUM 0 #define PREF_ADDR_SEQ_NUM 1 @@ -124,7 +124,7 @@ enum { }; typedef struct rcid_st { - OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff retire == 1 */ + OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff RETIRING */ QUIC_CONN_ID cid; /* The actual CID string for this RCID */ uint64_t seq_num; @@ -162,6 +162,11 @@ struct quic_rcidm_st { /* * The current RCID we prefer to use (value undefined if * !have_preferred_rcid). + * + * This is preferentially set to a numbered RCID (represented by an RCID + * object) if we have one (in which case preferred_rcid == cur_rcid->cid); + * otherwise it is set to one of the unnumbered RCIDs (the Initial ODCID or + * Retry ODCID) if available (and cur_rcid == NULL). */ QUIC_CONN_ID preferred_rcid; @@ -189,11 +194,11 @@ struct quic_rcidm_st { PRIORITY_QUEUE_OF(RCID) *rcids; /* - * Current RCID we are using. This may differ from the first item in the - * priority queue if we received NCID frames out of order. For example if we - * get seq 5, switch to it immediately, then get seq 4, we want to keep - * using seq 5 until we decide to roll again rather than immediately switch - * to seq 4. Never points to an object on the retiring_list. + * Current RCID object we are using. This may differ from the first item in + * the priority queue if we received NCID frames out of order. For example + * if we get seq 5, switch to it immediately, then get seq 4, we want to + * keep using seq 5 until we decide to roll again rather than immediately + * switch to seq 4. Never points to an object on the retiring_list. */ RCID *cur_rcid; @@ -229,6 +234,14 @@ struct quic_rcidm_st { unsigned int roll_requested : 1; }; +/* + * Caller must periodically pop retired RCIDs and handle them. If the caller + * fails to do so, fail safely rather than start exhibiting integer rollover. + * Limit the total number of numbered RCIDs to an implausibly large but safe + * value. + */ +#define MAX_NUMBERED_RCIDS (SIZE_MAX / 2) + static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid, unsigned int state); @@ -254,7 +267,6 @@ static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid) || rcid->state == RCID_STATE_RETIRING); assert(rcidm->num_changes == 0 || rcidm->handshake_complete); assert(rcid->state != RCID_STATE_RETIRING || rcidm->num_retiring > 0); - assert(rcidm->num_retiring < SIZE_MAX / 2); } static int rcid_cmp(const RCID *a, const RCID *b) @@ -263,10 +275,6 @@ static int rcid_cmp(const RCID *a, const RCID *b) return -1; if (a->seq_num > b->seq_num) return 1; - if ((uintptr_t)a < (uintptr_t)b) - return -1; - if ((uintptr_t)a > (uintptr_t)b) - return 1; return 0; } @@ -337,7 +345,9 @@ static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num, RCID *rcid; if (cid->id_len < 1 || cid->id_len > QUIC_MAX_CONN_ID_LEN - || seq_num > OSSL_QUIC_VLINT_MAX) + || seq_num > OSSL_QUIC_VLINT_MAX + || ossl_pqueue_RCID_num(rcidm->rcids) + rcidm->num_retiring + > MAX_NUMBERED_RCIDS) return NULL; if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL) @@ -351,7 +361,6 @@ static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num, rcid->state = RCID_STATE_PENDING; if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) { - assert(0); OPENSSL_free(rcid); return NULL; } @@ -501,7 +510,7 @@ static void rcidm_update(QUIC_RCIDM *rcidm) * If there are no RCIDs from NCID frames we can use, go through the various * kinds of bootstrapping RCIDs we can use in order of priority. */ - if (rcidm->added_retry_odcid) { + if (rcidm->added_retry_odcid && !rcidm->handshake_complete) { rcidm_set_preferred_rcid(rcidm, &rcidm->retry_odcid); return; } diff --git a/test/quic_rcidm_test.c b/test/quic_rcidm_test.c index 3e841bed569ab..ad1c1ac588dc1 100644 --- a/test/quic_rcidm_test.c +++ b/test/quic_rcidm_test.c @@ -16,6 +16,11 @@ static const QUIC_CONN_ID cid8_3 = { 8, { 3 } }; static const QUIC_CONN_ID cid8_4 = { 8, { 4 } }; static const QUIC_CONN_ID cid8_5 = { 8, { 5 } }; +/* + * 0: Client, Initial ODCID + * 1: Client, Initial ODCID + Retry ODCID + * 2: Server, doesn't start with Initial ODCID + */ static int test_rcidm(int idx) { int testresult = 0; From 0856bf519ffc7707fc01b763aed47e357a513820 Mon Sep 17 00:00:00 2001 From: Fs Date: Sat, 6 Jan 2024 08:43:22 +0800 Subject: [PATCH 58/81] uplink-x86_64.pl: make x86_64-xlate.pl accept $flavour parameter Match behavior of all other x86_64 asm. CLA: trivial Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23219) --- ms/uplink-x86_64.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ms/uplink-x86_64.pl b/ms/uplink-x86_64.pl index 5564c2c7bab1c..8b28949ccf8ef 100755 --- a/ms/uplink-x86_64.pl +++ b/ms/uplink-x86_64.pl @@ -8,9 +8,10 @@ # $output is the last argument if it looks like a file (it has an extension) $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef; +$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef; $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; -open OUT,"| \"$^X\" \"${dir}../crypto/perlasm/x86_64-xlate.pl\" \"$output\"" +open OUT,"| \"$^X\" \"${dir}../crypto/perlasm/x86_64-xlate.pl\" $flavour \"$output\"" or die "can't call ${dir}../crypto/perlasm/x86_64-xlate.pl: $!"; *STDOUT=*OUT; push(@INC,"${dir}."); From 576a3572bebf6115df1c03527114cbf74d06f861 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Thu, 4 Jan 2024 09:37:39 +0100 Subject: [PATCH 59/81] Fix partial block encryption in cfb and ofb for s390x Use the number of processed bytes information (num) from the generic cipher context for the partial block handling in cfb and ofb, instead of keep this information in the s390x-specific part of the cipher context. The information in the generic context is reset properly, even if the context is re-initialized without resetting the key or iv. Fixes: #23175 Signed-off-by: Holger Dengler Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23201) --- providers/implementations/ciphers/cipher_aes.h | 1 - .../implementations/ciphers/cipher_aes_hw_s390x.inc | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/providers/implementations/ciphers/cipher_aes.h b/providers/implementations/ciphers/cipher_aes.h index 7eaf76c8c47db..86a30ab145fc3 100644 --- a/providers/implementations/ciphers/cipher_aes.h +++ b/providers/implementations/ciphers/cipher_aes.h @@ -44,7 +44,6 @@ typedef struct prov_aes_ctx_st { /* KMO-AES/KMF-AES parameter block - end */ } param; unsigned int fc; - int res; } s390x; #endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */ } plat; diff --git a/providers/implementations/ciphers/cipher_aes_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc index c8282dbd08a9c..0939b147e64cb 100644 --- a/providers/implementations/ciphers/cipher_aes_hw_s390x.inc +++ b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc @@ -58,7 +58,6 @@ static int s390x_aes_ofb128_initkey(PROV_CIPHER_CTX *dat, memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen); adat->plat.s390x.fc = S390X_AES_FC(keylen); - adat->plat.s390x.res = 0; return 1; } @@ -66,7 +65,7 @@ static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, const unsigned char *in, size_t len) { PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; - int n = adat->plat.s390x.res; + int n = dat->num; int rem; memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen); @@ -102,7 +101,7 @@ static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, } memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen); - adat->plat.s390x.res = n; + dat->num = n; return 1; } @@ -113,7 +112,6 @@ static int s390x_aes_cfb128_initkey(PROV_CIPHER_CTX *dat, adat->plat.s390x.fc = S390X_AES_FC(keylen); adat->plat.s390x.fc |= 16 << 24; /* 16 bytes cipher feedback */ - adat->plat.s390x.res = 0; memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen); return 1; } @@ -123,7 +121,7 @@ static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, { PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT; - int n = adat->plat.s390x.res; + int n = dat->num; int rem; unsigned char tmp; @@ -164,7 +162,7 @@ static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, } memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen); - adat->plat.s390x.res = n; + dat->num = n; return 1; } From f9ccd209c3d121668c51a992613c698f2a774cb3 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Fri, 5 Jan 2024 14:16:53 +0100 Subject: [PATCH 60/81] Fix partial block encryption in cfb and ofb for s390x (legacy) Use the number of processed bytes information (num) from the generic cipher context for the partial block handling in cfb and ofb also in s390x-legacy code. For more details see 4df92c1a14 ("Fix partial block encryption in cfb and ofb for s390x"). Signed-off-by: Holger Dengler Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23201) --- crypto/evp/e_aes.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index 450ebe8a0d37d..0d61f4e49fda6 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -885,8 +885,6 @@ typedef struct { /* KMO-AES parameter block - end */ } kmo; unsigned int fc; - - int res; } S390X_AES_OFB_CTX; typedef struct { @@ -903,8 +901,6 @@ typedef struct { /* KMF-AES parameter block - end */ } kmf; unsigned int fc; - - int res; } S390X_AES_CFB_CTX; typedef struct { @@ -1068,7 +1064,6 @@ static int s390x_aes_ofb_init_key(EVP_CIPHER_CTX *ctx, memcpy(cctx->kmo.param.cv, iv, ivlen); memcpy(cctx->kmo.param.k, key, keylen); cctx->fc = S390X_AES_FC(keylen); - cctx->res = 0; return 1; } @@ -1078,7 +1073,7 @@ static int s390x_aes_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, S390X_AES_OFB_CTX *cctx = EVP_C_DATA(S390X_AES_OFB_CTX, ctx); const int ivlen = EVP_CIPHER_CTX_get_iv_length(ctx); unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx); - int n = cctx->res; + int n = ctx->num; int rem; memcpy(cctx->kmo.param.cv, iv, ivlen); @@ -1111,7 +1106,7 @@ static int s390x_aes_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, } memcpy(iv, cctx->kmo.param.cv, ivlen); - cctx->res = n; + ctx->num = n; return 1; } @@ -1137,7 +1132,6 @@ static int s390x_aes_cfb_init_key(EVP_CIPHER_CTX *ctx, if (!enc) cctx->fc |= S390X_DECRYPT; - cctx->res = 0; memcpy(cctx->kmf.param.cv, iv, ivlen); memcpy(cctx->kmf.param.k, key, keylen); return 1; @@ -1151,7 +1145,7 @@ static int s390x_aes_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const int enc = EVP_CIPHER_CTX_is_encrypting(ctx); const int ivlen = EVP_CIPHER_CTX_get_iv_length(ctx); unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx); - int n = cctx->res; + int n = ctx->num; int rem; unsigned char tmp; @@ -1197,7 +1191,7 @@ static int s390x_aes_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, } memcpy(iv, cctx->kmf.param.cv, ivlen); - cctx->res = n; + ctx->num = n; return 1; } From 3cb1b51dddf4deaf5e3886b827f3245d81670bc7 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Thu, 4 Jan 2024 19:25:08 +0100 Subject: [PATCH 61/81] Add tests for re-using cipher contexts Add test case for re-using a cipher context with the same key, iv and cipher. It detects, if the hardware-specific cipher context is reset correctly, like reported in issue #23175. This test has encrypt and decrypt iterations for cfb128 and ofb128. All iteations use the same key, iv and plaintext. Signed-off-by: Holger Dengler Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23201) --- test/evp_extra_test.c | 77 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 131879b8e227d..32624a4b59789 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -493,6 +493,10 @@ static const unsigned char cfbPlaintext[] = { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }; +static const unsigned char cfbPlaintext_partial[] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, + 0x73, 0x93, 0x17, 0x2A, 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, +}; static const unsigned char gcmDefaultPlaintext[16] = { 0 }; @@ -509,6 +513,16 @@ static const unsigned char cfbCiphertext[] = { 0xE8, 0x3C, 0xFB, 0x4A }; +static const unsigned char cfbCiphertext_partial[] = { + 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, 0x33, 0x34, 0x49, 0xF8, + 0xE8, 0x3C, 0xFB, 0x4A, 0x0D, 0x4A, 0x71, 0x82, 0x90, 0xF0, 0x9A, 0x35 +}; + +static const unsigned char ofbCiphertext_partial[] = { + 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, 0x33, 0x34, 0x49, 0xF8, + 0xE8, 0x3C, 0xFB, 0x4A, 0xB2, 0x65, 0x64, 0x38, 0x26, 0xD2, 0xBC, 0x09 +}; + static const unsigned char gcmDefaultCiphertext[] = { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 @@ -3942,6 +3956,30 @@ static const EVP_INIT_TEST_st evp_init_tests[] = { } }; +/* use same key, iv and plaintext for cfb and ofb */ +static const EVP_INIT_TEST_st evp_reinit_tests[] = { + { + "aes-128-cfb", kCFBDefaultKey, iCFBIV, cfbPlaintext_partial, + cfbCiphertext_partial, NULL, 0, sizeof(cfbPlaintext_partial), + sizeof(cfbCiphertext_partial), 0, 0, 1, 0 + }, + { + "aes-128-cfb", kCFBDefaultKey, iCFBIV, cfbCiphertext_partial, + cfbPlaintext_partial, NULL, 0, sizeof(cfbCiphertext_partial), + sizeof(cfbPlaintext_partial), 0, 0, 0, 0 + }, + { + "aes-128-ofb", kCFBDefaultKey, iCFBIV, cfbPlaintext_partial, + ofbCiphertext_partial, NULL, 0, sizeof(cfbPlaintext_partial), + sizeof(ofbCiphertext_partial), 0, 0, 1, 0 + }, + { + "aes-128-ofb", kCFBDefaultKey, iCFBIV, ofbCiphertext_partial, + cfbPlaintext_partial, NULL, 0, sizeof(ofbCiphertext_partial), + sizeof(cfbPlaintext_partial), 0, 0, 0, 0 + }, +}; + static int evp_init_seq_set_iv(EVP_CIPHER_CTX *ctx, const EVP_INIT_TEST_st *t) { int res = 0; @@ -4046,6 +4084,44 @@ static int test_evp_init_seq(int idx) return testresult; } +/* + * Test re-initialization of cipher context without changing key or iv. + * The result of both iteration should be the same. + */ +static int test_evp_reinit_seq(int idx) +{ + int outlen1, outlen2, outlen_final; + int testresult = 0; + unsigned char outbuf1[1024]; + unsigned char outbuf2[1024]; + const EVP_INIT_TEST_st *t = &evp_reinit_tests[idx]; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *type = NULL; + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_ptr(type = EVP_CIPHER_fetch(testctx, t->cipher, testpropq)) + /* setup cipher context */ + || !TEST_true(EVP_CipherInit_ex2(ctx, type, t->key, t->iv, t->initenc, NULL)) + /* first iteration */ + || !TEST_true(EVP_CipherUpdate(ctx, outbuf1, &outlen1, t->input, t->inlen)) + || !TEST_true(EVP_CipherFinal_ex(ctx, outbuf1, &outlen_final)) + /* check test results iteration 1 */ + || !TEST_mem_eq(t->expected, t->expectedlen, outbuf1, outlen1 + outlen_final) + /* now re-init the context (same cipher, key and iv) */ + || !TEST_true(EVP_CipherInit_ex2(ctx, NULL, NULL, NULL, -1, NULL)) + /* second iteration */ + || !TEST_true(EVP_CipherUpdate(ctx, outbuf2, &outlen2, t->input, t->inlen)) + || !TEST_true(EVP_CipherFinal_ex(ctx, outbuf2, &outlen_final)) + /* check test results iteration 2 */ + || !TEST_mem_eq(t->expected, t->expectedlen, outbuf2, outlen2 + outlen_final)) + goto err; + testresult = 1; + err: + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(type); + return testresult; +} + typedef struct { const unsigned char *input; const unsigned char *expected; @@ -5625,6 +5701,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_evp_init_seq, OSSL_NELEM(evp_init_tests)); ADD_ALL_TESTS(test_evp_reset, OSSL_NELEM(evp_reset_tests)); + ADD_ALL_TESTS(test_evp_reinit_seq, OSSL_NELEM(evp_reinit_tests)); ADD_ALL_TESTS(test_gcm_reinit, OSSL_NELEM(gcm_reinit_tests)); ADD_ALL_TESTS(test_evp_updated_iv, OSSL_NELEM(evp_updated_iv_tests)); ADD_ALL_TESTS(test_ivlen_change, OSSL_NELEM(ivlen_change_ciphers)); From 0981c20f8efa68bf9d68d7715280f83812c19a7e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 7 Dec 2023 16:56:39 -0500 Subject: [PATCH 62/81] Fix NULL pointer deref when parsing the stable section When parsing the stable section of a config such as this: openssl_conf = openssl_init [openssl_init] stbl_section = mstbl [mstbl] id-tc26 = min Can lead to a SIGSEGV, as the parsing code doesnt recognize min as a proper section name without a trailing colon to associate it with a value. As a result the stack of configuration values has an entry with a null value in it, which leads to the SIGSEGV in do_tcreate when we attempt to pass NULL to strtoul. Fix it by skipping any entry in the config name/value list that has a null value, prior to passing it to stroul Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22988) --- crypto/asn1/asn_mstbl.c | 6 +- test/asn1_stable_parse_test.c | 81 +++++++++++++++++++ test/build.info | 6 +- test/recipes/04-test_asn1_stable_parse.t | 24 ++++++ .../asn1_stable_parse.cnf | 16 ++++ 5 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 test/asn1_stable_parse_test.c create mode 100644 test/recipes/04-test_asn1_stable_parse.t create mode 100644 test/recipes/04-test_asn1_stable_parse_data/asn1_stable_parse.cnf diff --git a/crypto/asn1/asn_mstbl.c b/crypto/asn1/asn_mstbl.c index 515d8181b692e..93c6f61bd95b5 100644 --- a/crypto/asn1/asn_mstbl.c +++ b/crypto/asn1/asn_mstbl.c @@ -72,6 +72,8 @@ static int do_tcreate(const char *value, const char *name) goto err; for (i = 0; i < sk_CONF_VALUE_num(lst); i++) { cnf = sk_CONF_VALUE_value(lst, i); + if (cnf->value == NULL) + goto err; if (strcmp(cnf->name, "min") == 0) { tbl_min = strtoul(cnf->value, &eptr, 0); if (*eptr) @@ -98,7 +100,9 @@ static int do_tcreate(const char *value, const char *name) if (rv == 0) { if (cnf) ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE, - "field=%s, value=%s", cnf->name, cnf->value); + "field=%s, value=%s", cnf->name, + cnf->value != NULL ? cnf->value + : value); else ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE, "name=%s, value=%s", name, value); diff --git a/test/asn1_stable_parse_test.c b/test/asn1_stable_parse_test.c new file mode 100644 index 0000000000000..491e575edd2a0 --- /dev/null +++ b/test/asn1_stable_parse_test.c @@ -0,0 +1,81 @@ +/* + * 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 +#include "testutil.h" + +static char *config_file = NULL; + +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_CONFIG_FILE, + OPT_TEST_ENUM +} OPTION_CHOICE; + +const OPTIONS *test_get_options(void) +{ + static const OPTIONS options[] = { + OPT_TEST_OPTIONS_DEFAULT_USAGE, + { "config", OPT_CONFIG_FILE, '<', + "The configuration file to use for the libctx" }, + { NULL } + }; + return options; +} + + +/* + * Test that parsing a config file with incorrect stable settings aren't parsed + * and appropriate errors are raised + */ +static int test_asn1_stable_parse(void) +{ + int testret = 0; + unsigned long errcode; + OSSL_LIB_CTX *newctx = OSSL_LIB_CTX_new(); + + if (!TEST_ptr(newctx)) + goto out; + + if (!TEST_int_eq(OSSL_LIB_CTX_load_config(newctx, config_file), 0)) + goto err; + + errcode = ERR_peek_error(); + if (ERR_GET_LIB(errcode) != ERR_LIB_ASN1) + goto err; + if (ERR_GET_REASON(errcode) != ASN1_R_INVALID_STRING_TABLE_VALUE) + goto err; + + ERR_clear_error(); + + testret = 1; +err: + OSSL_LIB_CTX_free(newctx); +out: + return testret; +} + +int setup_tests(void) +{ + OPTION_CHOICE o; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_CONFIG_FILE: + config_file = opt_arg(); + break; + default: + return 0; + } + } + + ADD_TEST(test_asn1_stable_parse); + return 1; +} diff --git a/test/build.info b/test/build.info index 7e1ce28522025..cbd610bc933f4 100644 --- a/test/build.info +++ b/test/build.info @@ -51,7 +51,7 @@ IF[{- !$disabled{tests} -}] bioprinttest sslapitest ssl_handshake_rtt_test dtlstest sslcorrupttest \ bio_enc_test pkey_meth_test pkey_meth_kdf_test evp_kdf_test uitest \ cipherbytes_test threadstest_fips threadpool_test \ - asn1_encode_test asn1_decode_test asn1_string_table_test \ + asn1_encode_test asn1_decode_test asn1_string_table_test asn1_stable_parse_test \ x509_time_test x509_dup_cert_test x509_check_cert_pkey_test \ recordlentest drbgtest rand_status_test sslbuffertest \ time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ @@ -686,6 +686,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[asn1_string_table_test]=../include ../apps/include DEPEND[asn1_string_table_test]=../libcrypto libtestutil.a + SOURCE[asn1_stable_parse_test]=asn1_stable_parse_test.c + INCLUDE[asn1_stable_parse_test]=../include ../apps/include + DEPEND[asn1_stable_parse_test]=../libcrypto libtestutil.a + SOURCE[time_offset_test]=time_offset_test.c INCLUDE[time_offset_test]=../include ../apps/include DEPEND[time_offset_test]=../libcrypto libtestutil.a diff --git a/test/recipes/04-test_asn1_stable_parse.t b/test/recipes/04-test_asn1_stable_parse.t new file mode 100644 index 0000000000000..a6fe6a3d8fe42 --- /dev/null +++ b/test/recipes/04-test_asn1_stable_parse.t @@ -0,0 +1,24 @@ +#! /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; +use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file data_dir/; +use OpenSSL::Test::Utils; +use Cwd qw(abs_path); + +BEGIN { +setup("test_asn1_stable_parse"); +} +my $config_path = srctop_file("test", "recipes", "04-test_asn1_stable_parse_data", "asn1_stable_parse.cnf"); + +plan tests => 1; + +ok(run(test(["asn1_stable_parse_test", "-config", $config_path])), + "Confirm that malformed entries in stable section are not parsed"); + diff --git a/test/recipes/04-test_asn1_stable_parse_data/asn1_stable_parse.cnf b/test/recipes/04-test_asn1_stable_parse_data/asn1_stable_parse.cnf new file mode 100644 index 0000000000000..28381a083b0a2 --- /dev/null +++ b/test/recipes/04-test_asn1_stable_parse_data/asn1_stable_parse.cnf @@ -0,0 +1,16 @@ +openssl_conf = openssl_init +config_diagnostics = 1 + +[openssl_init] +s = mstbl + +[mstbl] +id-tc26 = min +id-tc27 = :::::: +id-tc28 = ,,,,,, +id-tc29 = :,:,:, +id-tc30 = n1:min +id-tc31 = n2:max +id-tc32 = n3: +id-tc33 = :0 + From 1d490694dfa790d8e47f8f2ea62ea1d9b1251179 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Fri, 27 Oct 2023 09:01:19 +0200 Subject: [PATCH 63/81] Fix the encoding of SM2 keys OpenSSL's encoding of SM2 keys used the SM2 OID for the algorithm OID where an AlgorithmIdentifier is encoded (for encoding into the structures PrivateKeyInfo and SubjectPublicKeyInfo). Such keys should be encoded as ECC keys. Fixes #22184 Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22529) --- CHANGES.md | 6 ++++++ .../implementations/encode_decode/encode_key2any.c | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 43b02502d8e01..eb16a6e24ed6e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -75,6 +75,12 @@ OpenSSL 3.2 ### Changes between 3.2.0 and 3.2.1 [xx XXX xxxx] + * Restore the encoding of SM2 PrivateKeyInfo and SubjectPublicKeyInfo to + have the contained AlgorithmIdentifier.algorithm set to id-ecPublicKey + rather than SM2. + + *Richard Levitte* + * The POLY1305 MAC (message authentication code) implementation in OpenSSL for PowerPC CPUs saves the contents of vector registers in different order than they are restored. Thus the contents of some of these vector diff --git a/providers/implementations/encode_decode/encode_key2any.c b/providers/implementations/encode_decode/encode_key2any.c index ae6d7d0a681d3..83a57ebe12db1 100644 --- a/providers/implementations/encode_decode/encode_key2any.c +++ b/providers/implementations/encode_decode/encode_key2any.c @@ -740,7 +740,15 @@ static int ec_pki_priv_to_der(const void *veckey, unsigned char **pder) # define ec_pem_type "EC" # ifndef OPENSSL_NO_SM2 -# define sm2_evp_type EVP_PKEY_SM2 +/* + * Albeit SM2 is a slightly different algorithm than ECDSA, the key type + * encoding (in all places where an AlgorithmIdentifier is produced, such + * as PrivateKeyInfo and SubjectPublicKeyInfo) is the same as for ECC keys + * according to the example in GM/T 0015-2012, appendix D.2. + * This leaves the distinction of SM2 keys to the EC group (which is found + * in AlgorithmIdentified.params). + */ +# define sm2_evp_type ec_evp_type # define sm2_input_type "SM2" # define sm2_pem_type "SM2" # endif From d4d9b57530b2ecdca6b4263b5841b42c820e5275 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 4 Jan 2024 12:42:05 +0100 Subject: [PATCH 64/81] Add test/recipes/15-test_gensm2.t, to test SM2 key generation results Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22529) --- test/recipes/15-test_gensm2.t | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 test/recipes/15-test_gensm2.t diff --git a/test/recipes/15-test_gensm2.t b/test/recipes/15-test_gensm2.t new file mode 100644 index 0000000000000..1c4c01a248894 --- /dev/null +++ b/test/recipes/15-test_gensm2.t @@ -0,0 +1,61 @@ +#! /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 strict; +use warnings; + +use File::Spec; +use OpenSSL::Test qw(:DEFAULT pipe); +use OpenSSL::Test::Utils; + +# These are special key generation tests for SM2 keys specifically, +# as they could be said to be a bit special in their encoding. +# This is an auxilliary test to 15-test_genec.t + +setup("test_gensm2"); + +plan skip_all => "This test is unsupported in a no-sm2 build" + if disabled("sm2"); + +plan tests => 2; + +# According to the example in GM/T 0015-2012, appendix D.2, +# generating an EC key with the named SM2 curve or generating +# an SM2 key should end up with the same encoding (apart from +# key private key field itself). This regular expressions +# shows us what 'openssl asn1parse' should display. + +my $sm2_re = qr| + ^ + .*?\Qcons: SEQUENCE\E\s+?\R + .*?\Qprim: INTEGER :00\E\R + .*?\Qcons: SEQUENCE\E\s+?\R + .*?\Qprim: OBJECT :id-ecPublicKey\E\R + .*?\Qprim: OBJECT :sm2\E\R + .*?\Qprim: OCTET STRING [HEX DUMP]:\E + |mx; + +my $cmd_genec = app([ 'openssl', 'genpkey', + '-algorithm', 'EC', + '-pkeyopt', 'ec_paramgen_curve:SM2', + '-pkeyopt', 'ec_param_enc:named_curve' ]); +my $cmd_gensm2 = app([ 'openssl', 'genpkey', '-algorithm', 'SM2' ]); +my $cmd_asn1parse = app([ 'openssl', 'asn1parse', '-i' ]); + +my $result_ec = join("", run(pipe($cmd_genec, $cmd_asn1parse), + capture => 1)); + +like($result_ec, $sm2_re, + "Check that 'genpkey -algorithm EC' resulted in a correctly encoded SM2 key"); + +my $result_sm2 = join("", run(pipe($cmd_gensm2, $cmd_asn1parse), + capture => 1)); + +like($result_sm2, $sm2_re, + "Check that 'genpkey -algorithm SM2' resulted in a correctly encoded SM2 key"); From d8184e982c65eee674d045da827c253c30fb59ff Mon Sep 17 00:00:00 2001 From: sharad3001 <46183881+sharad3001@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:30:58 +0530 Subject: [PATCH 65/81] ossl_rsa_fips186_4_gen_prob_primes(): Remove unused Xpout and Xqout CLA: trivial Reviewed-by: Tom Cosgrove Reviewed-by: Kurt Roeckx Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23253) --- crypto/rsa/rsa_sp800_56b_gen.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/crypto/rsa/rsa_sp800_56b_gen.c b/crypto/rsa/rsa_sp800_56b_gen.c index bcc0fceab0aa3..1e5cff56b94e2 100644 --- a/crypto/rsa/rsa_sp800_56b_gen.c +++ b/crypto/rsa/rsa_sp800_56b_gen.c @@ -30,7 +30,6 @@ * test Object used for CAVS testing only.that contains.. * p1, p2 The returned auxiliary primes for p. * If NULL they are not returned. - * Xpout An optionally returned random number used during generation of p. * Xp An optional passed in value (that is random number used during * generation of p). * Xp1, Xp2 Optionally passed in randomly generated numbers from which @@ -38,7 +37,6 @@ * are generated internally. * q1, q2 The returned auxiliary primes for q. * If NULL they are not returned. - * Xqout An optionally returned random number used during generation of q. * Xq An optional passed in value (that is random number used during * generation of q). * Xq1, Xq2 Optionally passed in randomly generated numbers from which @@ -50,7 +48,7 @@ * cb An optional BIGNUM callback. * Returns: 1 if successful, or 0 otherwise. * Notes: - * p1, p2, q1, q2, Xpout, Xqout are returned if they are not NULL. + * p1, p2, q1, q2 are returned if they are not NULL. * Xp, Xp1, Xp2, Xq, Xq1, Xq2 are optionally passed in. * (Required for CAVS testing). */ @@ -65,7 +63,6 @@ int ossl_rsa_fips186_4_gen_prob_primes(RSA *rsa, RSA_ACVP_TEST *test, BIGNUM *p1 = NULL, *p2 = NULL; BIGNUM *q1 = NULL, *q2 = NULL; /* Intermediate BIGNUMS that can be input for testing */ - BIGNUM *Xpout = NULL, *Xqout = NULL; BIGNUM *Xp = NULL, *Xp1 = NULL, *Xp2 = NULL; BIGNUM *Xq = NULL, *Xq1 = NULL, *Xq2 = NULL; @@ -105,8 +102,8 @@ int ossl_rsa_fips186_4_gen_prob_primes(RSA *rsa, RSA_ACVP_TEST *test, BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); - Xpo = (Xpout != NULL) ? Xpout : BN_CTX_get(ctx); - Xqo = (Xqout != NULL) ? Xqout : BN_CTX_get(ctx); + Xpo = BN_CTX_get(ctx); + Xqo = BN_CTX_get(ctx); if (tmp == NULL || Xpo == NULL || Xqo == NULL) goto err; BN_set_flags(Xpo, BN_FLG_CONSTTIME); @@ -150,9 +147,9 @@ int ossl_rsa_fips186_4_gen_prob_primes(RSA *rsa, RSA_ACVP_TEST *test, ret = 1; err: /* Zeroize any internally generated values that are not returned */ - if (Xpo != Xpout) + if (Xpo != NULL) BN_clear(Xpo); - if (Xqo != Xqout) + if (Xqo != NULL) BN_clear(Xqo); BN_clear(tmp); From df04e81794ac3083804c34c173eb2b2fa55d373d Mon Sep 17 00:00:00 2001 From: barracuda156 Date: Wed, 10 Jan 2024 06:35:33 +0800 Subject: [PATCH 66/81] aes_platform.h, gcm128.c: fix Darwin PowerPC macro to include ppc64 Current PowerPC-related defines omit Darwin ppc64 case. Use __POWERPC__ in place of __ppc__ + __ppc64__ Fixes #23220 CLA: trivial Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23245) --- crypto/modes/gcm128.c | 2 +- include/crypto/aes_platform.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/modes/gcm128.c b/crypto/modes/gcm128.c index 6f293ef7944d3..de9137c927876 100644 --- a/crypto/modes/gcm128.c +++ b/crypto/modes/gcm128.c @@ -393,7 +393,7 @@ void gcm_init_vis3(u128 Htable[16], const u64 Xi[2]); void gcm_gmult_vis3(u64 Xi[2], const u128 Htable[16]); void gcm_ghash_vis3(u64 Xi[2], const u128 Htable[16], const u8 *inp, size_t len); -# elif defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC)) +# elif defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC)) # include "crypto/ppc_arch.h" # define GHASH_ASM_PPC void gcm_init_p8(u128 Htable[16], const u64 Xi[2]); diff --git a/include/crypto/aes_platform.h b/include/crypto/aes_platform.h index 51fc5ba2111c6..cf4a94b86edf0 100644 --- a/include/crypto/aes_platform.h +++ b/include/crypto/aes_platform.h @@ -60,7 +60,7 @@ void AES_xts_decrypt(const unsigned char *inp, unsigned char *out, size_t len, # endif /* AES_XTS_ASM */ # if defined(OPENSSL_CPUID_OBJ) -# if (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC)) +# if (defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC)) # include "crypto/ppc_arch.h" # ifdef VPAES_ASM # define VPAES_CAPABLE (OPENSSL_ppccap_P & PPC_ALTIVEC) From 4e5bf933131863e0459d7b39931d464fef77b078 Mon Sep 17 00:00:00 2001 From: Job Snijders Date: Wed, 10 Jan 2024 17:15:52 +0000 Subject: [PATCH 67/81] Add apps/x509 -set_issuer & -set_subject option to override issuer & subject This changeset adds the counterpart to the '-subj' option to allow overriding the Issuer. For consistency, the `-subj` option is aliased to `-set_subject`. The issuer can be specified as following apps/openssl x509 -new -set_issuer '/CN=example-nro-ta' -subj '/CN=2a7dd1d787d793e4c8af56e197d4eed92af6ba13' ... This is useful in constructing specific test-cases or rechaining PKI trees Joint work with George Michaelson (@geeohgeegeeoh) Reviewed-by: Neil Horman Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23257) --- CHANGES.md | 6 ++++++ apps/x509.c | 26 ++++++++++++++++++++------ doc/man1/openssl-x509.pod.in | 21 +++++++++++++++++---- test/recipes/25-test_x509.t | 11 ++++++++++- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index eb16a6e24ed6e..58d06ae49847c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -36,6 +36,12 @@ OpenSSL 3.3 *Neil Horman* + * Added `-set_issuer` and `-set_subject` options to `openssl x509` to + override the Issuer and Subject when creating a certificate. The `-subj` + option now is an alias for `-set_subject`. + + *Job Snijders, George Michaelson* + * OPENSSL_sk_push() and sk__push() functions now return 0 instead of -1 if called with a NULL stack argument. diff --git a/apps/x509.c b/apps/x509.c index 578af2364fc12..ce3fda671665f 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -43,7 +43,7 @@ typedef enum OPTION_choice { OPT_INFORM, OPT_OUTFORM, OPT_KEYFORM, OPT_REQ, OPT_CAFORM, OPT_CAKEYFORM, OPT_VFYOPT, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE, OPT_EXTENSIONS, OPT_IN, OPT_OUT, OPT_KEY, OPT_SIGNKEY, OPT_CA, OPT_CAKEY, - OPT_CASERIAL, OPT_SET_SERIAL, OPT_NEW, OPT_FORCE_PUBKEY, OPT_SUBJ, + OPT_CASERIAL, OPT_SET_SERIAL, OPT_NEW, OPT_FORCE_PUBKEY, OPT_ISSU, OPT_SUBJ, OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_DATEOPT, OPT_NAMEOPT, OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL, OPT_MODULUS, OPT_PUBKEY, OPT_X509TOREQ, OPT_TEXT, OPT_HASH, @@ -138,7 +138,9 @@ const OPTIONS x509_options[] = { "Number of days until newly generated certificate expires - default 30"}, {"preserve_dates", OPT_PRESERVE_DATES, '-', "Preserve existing validity dates"}, - {"subj", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, + {"set_issuer", OPT_ISSU, 's', "Set or override certificate issuer"}, + {"set_subject", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, + {"subj", OPT_SUBJ, 's', "Alias for -set_subject"}, {"force_pubkey", OPT_FORCE_PUBKEY, '<', "Key to be placed in new certificate or certificate request"}, {"clrext", OPT_CLREXT, '-', @@ -262,8 +264,8 @@ int x509_main(int argc, char **argv) EVP_PKEY *privkey = NULL, *CAkey = NULL, *pubkey = NULL; EVP_PKEY *pkey; int newcert = 0; - char *subj = NULL, *digest = NULL; - X509_NAME *fsubj = NULL; + char *issu = NULL, *subj = NULL, *digest = NULL; + X509_NAME *fissu = NULL, *fsubj = NULL; const unsigned long chtype = MBSTRING_ASC; const int multirdn = 1; STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL; @@ -425,6 +427,9 @@ int x509_main(int argc, char **argv) case OPT_FORCE_PUBKEY: pubkeyfile = opt_arg(); break; + case OPT_ISSU: + issu = opt_arg(); + break; case OPT_SUBJ: subj = opt_arg(); break; @@ -651,6 +656,9 @@ int x509_main(int argc, char **argv) goto err; } } + if (issu != NULL + && (fissu = parse_name(issu, chtype, multirdn, "issuer")) == NULL) + goto end; if (subj != NULL && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL) goto end; @@ -830,8 +838,13 @@ int x509_main(int argc, char **argv) if (reqfile || newcert || privkey != NULL || CAfile != NULL) { if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) goto end; - if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) - goto end; + if (fissu != NULL) { + if (!X509_set_issuer_name(x, fissu)) + goto end; + } else { + if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) + goto end; + } } X509V3_set_ctx(&ext_ctx, issuer_cert, x, NULL, NULL, X509V3_CTX_REPLACE); @@ -1079,6 +1092,7 @@ int x509_main(int argc, char **argv) NCONF_free(extconf); BIO_free_all(out); X509_STORE_free(ctx); + X509_NAME_free(fissu); X509_NAME_free(fsubj); X509_REQ_free(req); X509_free(x); diff --git a/doc/man1/openssl-x509.pod.in b/doc/man1/openssl-x509.pod.in index 2d7a1b859ac4a..3a5bd25d56bec 100644 --- a/doc/man1/openssl-x509.pod.in +++ b/doc/man1/openssl-x509.pod.in @@ -56,6 +56,8 @@ B B [B<-next_serial>] [B<-days> I] [B<-preserve_dates>] +[B<-set_issuer> I] +[B<-set_subject> I] [B<-subj> I] [B<-force_pubkey> I] [B<-clrext>] @@ -123,7 +125,7 @@ see L. Generate a certificate from scratch, not using an input certificate or certificate request. So this excludes the B<-in> and B<-req> options. -Instead, the B<-subj> option needs to be given. +Instead, the B<-set_subject> option needs to be given. The public key to include can be given with the B<-force_pubkey> option and defaults to the key given with the B<-key> (or B<-signkey>) option, which implies self-signature. @@ -386,10 +388,17 @@ When signing a certificate, preserve "notBefore" and "notAfter" dates of any input certificate instead of adjusting them to current time and duration. Cannot be used together with the B<-days> option. -=item B<-subj> I +=item B<-set_issuer> I + +When a certificate is created set its issuer name to the given value. + +See B<-set_subject> on how the arg must be formatted. + +=item B<-set_subject> I When a certificate is created set its subject name to the given value. -When the certificate is self-signed the issuer name is set to the same value. +When the certificate is self-signed the issuer name is set to the same value, +unless the B<-set_issuer> option is given. The arg must be formatted as C. Special characters may be escaped by C<\> (backslash), whitespace is retained. @@ -405,6 +414,10 @@ C This option can be used with the B<-new> and B<-force_pubkey> options to create a new certificate without providing an input certificate or certificate request. +=item B<-subj> I + +This option is an alias of B<-set_subject>. + =item B<-force_pubkey> I When a new certificate or certificate request is created @@ -413,7 +426,7 @@ instead of the key contained in the input or given with the B<-key> (or B<-signkey>) option. If the input contains no public key but a private key, its public part is used. -This option can be used in conjunction with b<-new> and B<-subj> +This option can be used in conjunction with b<-new> and B<-set_subject> to directly generate a certificate containing any desired public key. This option is also useful for creating self-issued certificates that are not diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 9b11169a98269..eeb8083506e1a 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 44; +plan tests => 46; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -81,6 +81,15 @@ ok(run(app(["openssl", "pkey", "-in", $pkey, "-pubout", "-out", $pubkey])) # not unlinking $pubkey # not unlinking $selfout +# test -set_issuer option +my $ca_issu = srctop_file(@certs, "ca-cert.pem"); # issuer cert +my $caout_issu = "ca-issu.out"; +ok(run(app(["openssl", "x509", "-new", "-force_pubkey", $key, "-subj", "/CN=EE", + "-set_issuer", "/CN=TEST-CA", "-extfile", $extfile, "-CA", $ca_issu, + "-CAkey", $pkey, "-text", "-out", $caout_issu]))); +ok(get_issuer($caout_issu) =~ /CN=TEST-CA/); +# not unlinking $caout + # simple way of directly producing a CA-signed cert with private/pubkey input my $ca = srctop_file(@certs, "ca-cert.pem"); # issuer cert my $caout = "ca-issued.out"; From 6b92a966e0de3ad848fcf11fbcab7ee8cae24ba1 Mon Sep 17 00:00:00 2001 From: Drokov Pavel Date: Thu, 11 Jan 2024 18:51:15 -0500 Subject: [PATCH 68/81] Check ASN1_OBJECT_new result CLA: trivial Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23270) --- crypto/objects/obj_dat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c index b0e1032ec2cf8..ebde56247761c 100644 --- a/crypto/objects/obj_dat.c +++ b/crypto/objects/obj_dat.c @@ -790,6 +790,10 @@ int OBJ_create(const char *oid, const char *sn, const char *ln) } else { /* Create a no-OID ASN1_OBJECT */ tmpoid = ASN1_OBJECT_new(); + if (tmpoid == NULL) { + ERR_raise(ERR_LIB_OBJ, ERR_R_ASN1_LIB); + return 0; + } } if (!ossl_obj_write_lock(1)) { From 7068e5e2dcc9a6e0c1cd3fab6d8a903681fe6b07 Mon Sep 17 00:00:00 2001 From: barracuda156 Date: Thu, 11 Jan 2024 22:28:00 +0800 Subject: [PATCH 69/81] poly1305_ieee754.c: fix PowerPC macros Fixes #23264 cla: trivial Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23267) --- crypto/poly1305/poly1305_ieee754.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crypto/poly1305/poly1305_ieee754.c b/crypto/poly1305/poly1305_ieee754.c index fa0ab1ed1d2fb..fd48adc98f877 100644 --- a/crypto/poly1305/poly1305_ieee754.c +++ b/crypto/poly1305/poly1305_ieee754.c @@ -69,7 +69,7 @@ typedef union { double d; u64 u; } elem64; #if defined(__x86_64__) || (defined(__PPC__) && defined(__LITTLE_ENDIAN__)) # define U8TOU32(p) (*(const u32 *)(p)) # define U32TO8(p,v) (*(u32 *)(p) = (v)) -#elif defined(__PPC__) +#elif defined(__PPC__) || defined(__POWERPC__) # define U8TOU32(p) ({u32 ret; asm ("lwbrx %0,0,%1":"=r"(ret):"b"(p)); ret; }) # define U32TO8(p,v) asm ("stwbrx %0,0,%1"::"r"(v),"b"(p):"memory") #elif defined(__s390x__) @@ -95,7 +95,7 @@ typedef struct { /* "round toward zero (truncate), mask all exceptions" */ #if defined(__x86_64__) static const u32 mxcsr = 0x7f80; -#elif defined(__PPC__) +#elif defined(__PPC__) || defined(__POWERPC__) static const u64 one = 1; #elif defined(__s390x__) static const u32 fpc = 1; @@ -134,7 +134,7 @@ int poly1305_init(void *ctx, const unsigned char key[16]) asm volatile ("stmxcsr %0":"=m"(mxcsr_orig)); asm volatile ("ldmxcsr %0"::"m"(mxcsr)); -#elif defined(__PPC__) +#elif defined(__PPC__) || defined(__POWERPC__) double fpscr_orig, fpscr = *(double *)&one; asm volatile ("mffs %0":"=f"(fpscr_orig)); @@ -207,7 +207,7 @@ int poly1305_init(void *ctx, const unsigned char key[16]) */ #if defined(__x86_64__) asm volatile ("ldmxcsr %0"::"m"(mxcsr_orig)); -#elif defined(__PPC__) +#elif defined(__PPC__) || defined(__POWERPC__) asm volatile ("mtfsf 255,%0"::"f"(fpscr_orig)); #elif defined(__s390x__) asm volatile ("lfpc %0"::"m"(fpc_orig)); @@ -256,7 +256,7 @@ void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, asm volatile ("stmxcsr %0":"=m"(mxcsr_orig)); asm volatile ("ldmxcsr %0"::"m"(mxcsr)); -#elif defined(__PPC__) +#elif defined(__PPC__) || defined(__POWERPC__) double fpscr_orig, fpscr = *(double *)&one; asm volatile ("mffs %0":"=f"(fpscr_orig)); @@ -416,7 +416,7 @@ void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, */ #if defined(__x86_64__) asm volatile ("ldmxcsr %0"::"m"(mxcsr_orig)); -#elif defined(__PPC__) +#elif defined(__PPC__) || defined(__POWERPC__) asm volatile ("mtfsf 255,%0"::"f"(fpscr_orig)); #elif defined(__s390x__) asm volatile ("lfpc %0"::"m"(fpc_orig)); From 441b3b7ba15d5dc6e034b030bd8b88ce596f53ba Mon Sep 17 00:00:00 2001 From: Akshat Maheshwari Date: Thu, 11 Jan 2024 22:51:59 +0530 Subject: [PATCH 70/81] Fix grammar in documentation CLA: trivial Reviewed-by: Paul Yang Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23266) --- doc/man3/SSL_get_error.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man3/SSL_get_error.pod b/doc/man3/SSL_get_error.pod index 27dd584687f30..c3ab1741b16f6 100644 --- a/doc/man3/SSL_get_error.pod +++ b/doc/man3/SSL_get_error.pod @@ -73,7 +73,7 @@ for a blocking B. See L for more information. For non-QUIC SSL objects, B is returned when the last -operation was a write to a nonblocking B and it was unable to sent all data +operation was a write to a nonblocking B and it was unable to send all data to the B. When the B is writable again, the same function can be called again. From 486ab0fb003d05f89620662260486d31bd3faa8c Mon Sep 17 00:00:00 2001 From: Drokov Pavel Date: Fri, 12 Jan 2024 02:10:17 -0500 Subject: [PATCH 71/81] Fix arithmetic expression overflow If the value of a->length is large (>= 2^12), then an integer overflow will occur for the signed type, which according to the C standard is UB. CLA: trivial Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23274) --- crypto/objects/obj_dat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c index ebde56247761c..30a63bbbd9b8a 100644 --- a/crypto/objects/obj_dat.c +++ b/crypto/objects/obj_dat.c @@ -128,7 +128,7 @@ static unsigned long added_obj_hash(const ADDED_OBJ *ca) a = ca->obj; switch (ca->type) { case ADDED_DATA: - ret = a->length << 20L; + ret = (unsigned long)a->length << 20UL; p = (unsigned char *)a->data; for (i = 0; i < a->length; i++) ret ^= p[i] << ((i * 3) % 24); From e09fc1d746a4fd15bb5c3d7bbbab950aadd005db Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 22 Dec 2023 16:25:56 +0100 Subject: [PATCH 72/81] Limit the execution time of RSA public key check Fixes CVE-2023-6237 If a large and incorrect RSA public key is checked with EVP_PKEY_public_check() the computation could take very long time due to no limit being applied to the RSA public key size and unnecessarily high number of Miller-Rabin algorithm rounds used for non-primality check of the modulus. Now the keys larger than 16384 bits (OPENSSL_RSA_MAX_MODULUS_BITS) will fail the check with RSA_R_MODULUS_TOO_LARGE error reason. Also the number of Miller-Rabin rounds was set to 5. Reviewed-by: Neil Horman Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23243) --- crypto/rsa/rsa_sp800_56b_check.c | 8 +++- test/recipes/91-test_pkey_check.t | 2 +- .../91-test_pkey_check_data/rsapub_17k.pem | 48 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 test/recipes/91-test_pkey_check_data/rsapub_17k.pem diff --git a/crypto/rsa/rsa_sp800_56b_check.c b/crypto/rsa/rsa_sp800_56b_check.c index e6b79e953dda1..9c855a7978a0c 100644 --- a/crypto/rsa/rsa_sp800_56b_check.c +++ b/crypto/rsa/rsa_sp800_56b_check.c @@ -289,6 +289,11 @@ int ossl_rsa_sp800_56b_check_public(const RSA *rsa) return 0; nbits = BN_num_bits(rsa->n); + if (nbits > OPENSSL_RSA_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_RSA, RSA_R_MODULUS_TOO_LARGE); + return 0; + } + #ifdef FIPS_MODULE /* * (Step a): modulus must be 2048 or 3072 (caveat from SP800-56Br1) @@ -324,7 +329,8 @@ int ossl_rsa_sp800_56b_check_public(const RSA *rsa) goto err; } - ret = ossl_bn_miller_rabin_is_prime(rsa->n, 0, ctx, NULL, 1, &status); + /* Highest number of MR rounds from FIPS 186-5 Section B.3 Table B.1 */ + ret = ossl_bn_miller_rabin_is_prime(rsa->n, 5, ctx, NULL, 1, &status); #ifdef FIPS_MODULE if (ret != 1 || status != BN_PRIMETEST_COMPOSITE_NOT_POWER_OF_PRIME) { #else diff --git a/test/recipes/91-test_pkey_check.t b/test/recipes/91-test_pkey_check.t index dc7cc64533af2..f8088df14d36c 100644 --- a/test/recipes/91-test_pkey_check.t +++ b/test/recipes/91-test_pkey_check.t @@ -70,7 +70,7 @@ push(@positive_tests, ( "dhpkey.pem" )) unless disabled("dh"); -my @negative_pubtests = (); +my @negative_pubtests = ("rsapub_17k.pem"); # Too big RSA public key push(@negative_pubtests, ( "dsapub_noparam.der" diff --git a/test/recipes/91-test_pkey_check_data/rsapub_17k.pem b/test/recipes/91-test_pkey_check_data/rsapub_17k.pem new file mode 100644 index 0000000000000..9a2eaedaf1b22 --- /dev/null +++ b/test/recipes/91-test_pkey_check_data/rsapub_17k.pem @@ -0,0 +1,48 @@ +-----BEGIN PUBLIC KEY----- +MIIIbzANBgkqhkiG9w0BAQEFAAOCCFwAMIIIVwKCCE4Ang+cE5H+hg3RbapDAHqR +B9lUnp2MlAwsZxQ/FhYepaR60bFQeumbu7817Eo5YLMObVI99hF1C4u/qcpD4Jph +gZt87/JAYDbP+DIh/5gUXCL9m5Fp4u7mvZaZdnlcftBvR1uKUTCAwc9pZ/Cfr8W2 +GzrRODzsNYnk2DcZMfe2vRDuDZRopE+Y+I72rom2SZLxoN547N1daM/M/CL9KVQ/ +XMI/YOpJrBI0jI3brMRhLkvLckwies9joufydlGbJkeil9H7/grj3fQZtFkZ2Pkj +b87XDzRVX7wsEpAgPJxskL3jApokCp1kQYKG+Uc3dKM9Ade6IAPK7VKcmbAQTYw2 +gZxsc28dtstazmfGz0ACCTSMrmbgWAM3oPL7RRzhrXDWgmYQ0jHefGh8SNTIgtPq +TuHxPYkDMQNaf0LmDGCxqlnf4b5ld3YaU8zZ/RqIRx5v/+w0rJUvU53qY1bYSnL1 +vbqKSnN2mip0GYyQ4AUgkS1NBV4rGYU/VTvzEjLfkg02KOtHKandvEoUjmZPzCT0 +V2ZhGc8K1UJNGYlIiHqCdwCBoghvly/pYajTkDXyd6BsukzA5H3IkZB1xDgl035j +/0Cr7QeZLEOdi9fPdSSaBT6OmD0WFuZfJF0wMr7ucRhWzPXvSensD9v7MBE7tNfH +SLeTSx8tLt8UeWriiM+0CnkPR1IOqMOxubOyf1eV8NQqEWm5wEQG/0IskbOKnaHa +PqLFJZn/bvyL3XK5OxVIJG3z6bnRDOMS9SzkjqgPdIO8tkySEHVSi/6iuGUltx3Y +Fmq6ye/r34ekyHPbfn6UuTON7joM6SIXb5bHM64x4iMVWx4hMvDjfy0UqfywAUyu +C1o7BExSMxxFG8GJcqR0K8akpPp7EM588PC+YuItoxzXgfUJnP3BQ1Beev2Ve7/J +xeGZH0N4ntfr+cuaLAakAER9zDglwChWflw3NNFgIdAgSxXv3XXx5xDXpdP4lxUo +F5zAN4Mero3yV90FaJl7Vhq/UFVidbwFc15jUDwaE0mKRcsBeVd3GOhoECAgE0id +aIPT20z8oVY0FyTJlRk7QSjo8WjJSrHY/Fn14gctX07ZdfkufyL6w+NijBdYluvB +nIrgHEvpkDEWoIa8qcx0EppoIcmqgMV2mTShfFYSybsO33Pm8WXec2FXjwhzs1Pi +R/BuIW8rHPI67xqWm0h8dEw11vtfi9a/BBBikFHe59KBjMTG+lW/gADNvRoTzGh7 +kN4+UVDS3jlSisRZZOn1XoeQtpubNYWgUsecjKy45IwIj8h1SHgn3wkmUesY0woN +mOdoNtq+NezN4RFtbCOHhxFVpKKDi/HQP2ro0ykkXMDjwEIVf2Lii1Mg9UP8m+Ux +AOqkTrIkdogkRx+70h7/wUOfDIFUq2JbKzqxJYamyEphcdAko7/B8efQKc61Z93O +f2SHa4++4WI7wIIx18v5KV4M/cRmrfc8w9WRkQN3gBT5AJMuqwcSHVXBWvNQeGmi +ScMh7X6cCZ0daEujqb8svq4WgsJ8UT4GaGBRIYtt7QUKEh+JQwNJzneRYZ3pzpaH +UJeeoYobMlkp3rM9cYzdq90nBQiI9Jsbim9m9ggb2dMOS5CsI9S/IuG2O5uTjfxx +wkwsd5nLDFtNXHYZ7W6XlVJ1Rc6zShnEmdCn3mmibb6OaMUmun2yl9ryEjVSoXLP +fSA8W9K9yNhKTRkzdXJfqlC+s/ovX2xBGxsuOoUDaXhRVz0qmpKIHeSFjIP4iXq4 +y8gDiwvM3HbZfvVonbg6siPwpn4uvw3hesojk1DKAENS52i6U3uK2fs1ALVxsFNS +Yh914rDu0Q3e4RXVhURaYzoEbLCot6WGYeCCfQOK0rkETMv+sTYYscC8/THuW7SL +HG5zy9Ed95N1Xmf8J+My7gM7ZFodGdHsWvdzEmqsdOFh6IVx/VfHFX0MDBq0t6lZ +eRvVgVCfu3gkYLwPScn/04E02vOom51ISKHsF/I11erC66jjNYV9BSpH8O7sAHxZ +EmPT2ZVVRSgivOHdQW/FZ3UZQQhVaVSympo2Eb4yWEMFn84Q8T+9Honj6gnB5PXz +chmeCsOMlcg1mwWwhn0k+OAWEZy7VRUk5Ahp0fBAGJgwBdqrZ3kM356DjUkVBiYq +4eHyvafNKmjf2mnFsI3g2NKRNyl1Lh63wyCFx60yYvBUfXF/W9PFJbD9CiP83kEW +gV36gxTsbOSfhpO1OXR90ODy0kx06XzWmJCUugK8u9bx4F/CjV+LIHExuNJiethC +A8sIup/MT0fWp4RO/SsVblGqfoqJTaPnhptQzeH2N07pbWkxeMuL6ppPuwFmfVjK +FJndqCVrAukcPEOQ16iVURuloJMudqYRc9QKkJFsnv0W/iMNbqQGmXe8Q/5qFiys +26NIQBiE2ad9hNLnoccEnmYSRgnW3ZPSKuq5TDdYyDqTZH2r8cam65pr3beKw2XC +xw4cc7VaxiwGC2Mg2wRmwwPaTjrcEt6sMa3RjwFEVBxBFyM26wnTEZsTBquCxV0J +pgERaeplkixP2Q0m7XAdlDaob973SM2vOoUgypzDchWmpx7u775bnOfU5CihwXl+ +k0i09WZuT8bPmhEAiGCw5sNzMkz1BC2cCZFfJIkE2vc/wXYOrGxBTJo0EKaUFswa +2dnP/u0bn+VksBUM7ywW9LJSXh4mN+tpzdeJtxEObKwX1I0dQxSPWmjd2++wMr9q +Unre5fCrDToy2H7C2VKSpuOCT2/Kv4JDQRWwI4KxQOpn0UknAGNmfBoTtpIZ3LEb +77oBUJdMQD7tQBBLL0a6f1TdK0dHVprWWawJ+gGFMiMQXqAqblHcxFKWuHv9bQID +AQAB +-----END PUBLIC KEY----- From 38b2508f638787842750aec9a75745e1d8786743 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 9 Jan 2024 18:08:22 +0100 Subject: [PATCH 73/81] Add CHANGES.md and NEWS.md entries for CVE-2023-6237 Reviewed-by: Neil Horman Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23243) --- CHANGES.md | 23 +++++++++++++++++++++++ NEWS.md | 6 +++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 58d06ae49847c..ffef5c25c9026 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -81,6 +81,28 @@ OpenSSL 3.2 ### Changes between 3.2.0 and 3.2.1 [xx XXX xxxx] + * When function EVP_PKEY_public_check() is called on RSA public keys, + a computation is done to confirm that the RSA modulus, n, is composite. + For valid RSA keys, n is a product of two or more large primes and this + computation completes quickly. However, if n is an overly large prime, + then this computation would take a long time. + + An application that calls EVP_PKEY_public_check() and supplies an RSA key + obtained from an untrusted source could be vulnerable to a Denial of Service + attack. + + The function EVP_PKEY_public_check() is not called from other OpenSSL + functions however it is called from the OpenSSL pkey command line + application. For that reason that application is also vulnerable if used + with the "-pubin" and "-check" options on untrusted data. + + To resolve this issue RSA keys larger than OPENSSL_RSA_MAX_MODULUS_BITS will + now fail the check immediately with an RSA_R_MODULUS_TOO_LARGE error reason. + + ([CVE-2023-6237]) + + *Tomáš Mráz* + * Restore the encoding of SM2 PrivateKeyInfo and SubjectPublicKeyInfo to have the contained AlgorithmIdentifier.algorithm set to id-ecPublicKey rather than SM2. @@ -20412,6 +20434,7 @@ ndif +[CVE-2023-6237]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6237 [CVE-2023-6129]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6129 [CVE-2023-5678]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5678 [CVE-2023-5363]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5363 diff --git a/NEWS.md b/NEWS.md index a41353e1a6fce..351f21034a75f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,7 +31,10 @@ OpenSSL 3.2 ### Major changes between OpenSSL 3.2.0 and OpenSSL 3.2.1 [under development] - * Fix POLY1305 MAC implementation corrupting vector registers on PowerPC + * Fixed Excessive time spent checking invalid RSA public keys + ([CVE-2023-6237]) + + * Fixed POLY1305 MAC implementation corrupting vector registers on PowerPC CPUs which support PowerISA 2.07 ([CVE-2023-6129]) @@ -1582,6 +1585,7 @@ OpenSSL 0.9.x +[CVE-2023-6237]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6237 [CVE-2023-6129]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6129 [CVE-2023-5678]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5678 [CVE-2023-5363]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5363 From ffeae4c4e7d779746c661e7fe17a0a21cc36c974 Mon Sep 17 00:00:00 2001 From: Gopal Sharma <67860577+gsharma-ad@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:18:41 +0530 Subject: [PATCH 74/81] Removed logically dead code from function i2r_issuer_sign_tool Since new_line is assigned with 0 in the very begging of the function check added at line no. 106 will never become true. Hence removing. CLA: trivial Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/23284) --- crypto/x509/v3_ist.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/crypto/x509/v3_ist.c b/crypto/x509/v3_ist.c index 4d5fe82f329e1..ccca198eb8fd9 100644 --- a/crypto/x509/v3_ist.c +++ b/crypto/x509/v3_ist.c @@ -103,9 +103,6 @@ static int i2r_issuer_sign_tool(X509V3_EXT_METHOD *method, return 0; } if (ist->signTool != NULL) { - if (new_line == 1) { - BIO_write(out, "\n", 1); - } BIO_printf(out, "%*ssignTool : ", indent, ""); BIO_write(out, ist->signTool->data, ist->signTool->length); new_line = 1; From 08cecb4448e990f7914ec1df97b1ee0ca9031643 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 11 Dec 2023 01:47:25 -0500 Subject: [PATCH 75/81] Add X509_STORE_get1_objects X509_STORE_get0_objects returns a pointer to the X509_STORE's storage, but this function is a bit deceptive. It is practically unusable in a multi-threaded program. See, for example, RUSTSEC-2023-0072, a security vulnerability caused by this OpenSSL API. One might think that, if no other threads are mutating the X509_STORE, it is safe to read the resulting list. However, the documention does not mention that other logically-const operations on the X509_STORE, notably certifcate verifications when a hash_dir is installed, will, under a lock, write to the X509_STORE. The X509_STORE also internally re-sorts the list on the first query. If the caller knows to call X509_STORE_lock and X509_STORE_unlock, it can work around this. But this is not obvious, and the documentation does not discuss how X509_STORE_lock is very rarely safe to use. E.g. one cannot call any APIs like X509_STORE_add_cert or X509_STORE_CTX_get1_issuer while holding the lock because those functions internally expect to take the lock. (X509_STORE_lock is another such API which is not safe to export as public API.) Rather than leave all this to the caller to figure out, the API should have returned a shallow copy of the list, refcounting the values. Then it could be internally locked and the caller can freely inspect the result without synchronization with the X509_STORE. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23224) --- crypto/x509/x509_lu.c | 30 ++++++++++++++++++++++++++++++ doc/man3/X509_STORE_get0_param.pod | 15 +++++++++++++-- include/openssl/x509_vfy.h.in | 1 + test/x509_load_cert_file_test.c | 27 ++++++++++++++++++++------- util/libcrypto.num | 1 + 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index 0ca7cb960d4fd..3fa4fee1e1e96 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -583,6 +583,36 @@ STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(const X509_STORE *xs) return xs->objs; } +static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj) +{ + X509_OBJECT *ret = X509_OBJECT_new(); + if (ret == NULL) + return NULL; + + ret->type = obj->type; + ret->data = obj->data; + X509_OBJECT_up_ref_count(ret); + return ret; +} + +STACK_OF(X509_OBJECT) *X509_STORE_get1_objects(X509_STORE *store) +{ + STACK_OF(X509_OBJECT) *objs; + + if (store == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (!x509_store_read_lock(store)) + return NULL; + + objs = sk_X509_OBJECT_deep_copy(store->objs, x509_object_dup, + X509_OBJECT_free); + X509_STORE_unlock(store); + return objs; +} + STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *store) { STACK_OF(X509) *sk; diff --git a/doc/man3/X509_STORE_get0_param.pod b/doc/man3/X509_STORE_get0_param.pod index 559c137285b83..d9dfb1b656fea 100644 --- a/doc/man3/X509_STORE_get0_param.pod +++ b/doc/man3/X509_STORE_get0_param.pod @@ -3,7 +3,7 @@ =head1 NAME X509_STORE_get0_param, X509_STORE_set1_param, -X509_STORE_get0_objects, X509_STORE_get1_all_certs +X509_STORE_get1_objects, X509_STORE_get0_objects, X509_STORE_get1_all_certs - X509_STORE setter and getter functions =head1 SYNOPSIS @@ -12,6 +12,7 @@ X509_STORE_get0_objects, X509_STORE_get1_all_certs X509_VERIFY_PARAM *X509_STORE_get0_param(const X509_STORE *xs); int X509_STORE_set1_param(X509_STORE *xs, const X509_VERIFY_PARAM *pm); + STACK_OF(X509_OBJECT) *X509_STORE_get1_objects(X509_STORE *xs); STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(const X509_STORE *xs); STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *xs); @@ -23,9 +24,15 @@ X509_STORE_get0_param() retrieves an internal pointer to the verification parameters for I. The returned pointer must not be freed by the calling application +X509_STORE_get1_objects() returns a snapshot of all objects in the store's X509 +cache. The cache contains B and B objects. The caller is +responsible for freeing the returned list. + X509_STORE_get0_objects() retrieves an internal pointer to the store's X509 object cache. The cache contains B and B objects. The -returned pointer must not be freed by the calling application. +returned pointer must not be freed by the calling application. If the store is +shared across multiple threads, it is not safe to use the result of this +function. Use X509_STORE_get1_objects() instead, which avoids this problem. X509_STORE_get1_all_certs() returns a list of all certificates in the store. The caller is responsible for freeing the returned list. @@ -37,6 +44,9 @@ B structure. X509_STORE_set1_param() returns 1 for success and 0 for failure. +X509_STORE_get1_objects() returns a pointer to a stack of the retrieved +objects on success, else NULL. + X509_STORE_get0_objects() returns a pointer to a stack of B. X509_STORE_get1_all_certs() returns a pointer to a stack of the retrieved @@ -51,6 +61,7 @@ L B and B were added in OpenSSL 1.1.0. B was added in OpenSSL 3.0. +B was added in OpenSSL 3.3. =head1 COPYRIGHT diff --git a/include/openssl/x509_vfy.h.in b/include/openssl/x509_vfy.h.in index 7a478d117ae25..2166ef0b06452 100644 --- a/include/openssl/x509_vfy.h.in +++ b/include/openssl/x509_vfy.h.in @@ -400,6 +400,7 @@ int X509_STORE_lock(X509_STORE *xs); int X509_STORE_unlock(X509_STORE *xs); int X509_STORE_up_ref(X509_STORE *xs); STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(const X509_STORE *xs); +STACK_OF(X509_OBJECT) *X509_STORE_get1_objects(X509_STORE *xs); STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *xs); STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *xs, const X509_NAME *nm); diff --git a/test/x509_load_cert_file_test.c b/test/x509_load_cert_file_test.c index 4a736071ae61e..001ed570d3cd7 100644 --- a/test/x509_load_cert_file_test.c +++ b/test/x509_load_cert_file_test.c @@ -15,19 +15,32 @@ static const char *chain; static int test_load_cert_file(void) { - int ret = 0; + int ret = 0, i; X509_STORE *store = NULL; X509_LOOKUP *lookup = NULL; STACK_OF(X509) *certs = NULL; + STACK_OF(X509_OBJECT) *objs = NULL; + + if (!TEST_ptr(store = X509_STORE_new()) + || !TEST_ptr(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) + || !TEST_true(X509_load_cert_file(lookup, chain, X509_FILETYPE_PEM)) + || !TEST_ptr(certs = X509_STORE_get1_all_certs(store)) + || !TEST_int_eq(sk_X509_num(certs), 4) + || !TEST_ptr(objs = X509_STORE_get1_objects(store)) + || !TEST_int_eq(sk_X509_OBJECT_num(objs), 4)) + goto err; + + for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { + const X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); + if (!TEST_int_eq(X509_OBJECT_get_type(obj), X509_LU_X509)) + goto err; + } - if (TEST_ptr(store = X509_STORE_new()) - && TEST_ptr(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) - && TEST_true(X509_load_cert_file(lookup, chain, X509_FILETYPE_PEM)) - && TEST_ptr(certs = X509_STORE_get1_all_certs(store)) - && TEST_int_eq(sk_X509_num(certs), 4)) - ret = 1; + ret = 1; +err: OSSL_STACK_OF_X509_free(certs); + sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free); X509_STORE_free(store); return ret; } diff --git a/util/libcrypto.num b/util/libcrypto.num index 9d92ca67cada8..f6e5a90ad73c7 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5543,3 +5543,4 @@ OSSL_CMP_ITAV_get0_certProfile ? 3_3_0 EXIST::FUNCTION:CMP OSSL_CMP_SRV_CTX_init_trans ? 3_3_0 EXIST::FUNCTION:CMP EVP_DigestSqueeze ? 3_3_0 EXIST::FUNCTION: ERR_pop ? 3_3_0 EXIST::FUNCTION: +X509_STORE_get1_objects ? 3_3_0 EXIST::FUNCTION: From 575117efe1e0eb8073c2d26ae3dff8926be00591 Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Fri, 12 Jan 2024 10:14:43 +0100 Subject: [PATCH 76/81] Error in s_server when -rev option is used with dtls. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23278) --- apps/s_server.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/s_server.c b/apps/s_server.c index 93f6cb2983f7d..b1164d10cc893 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -1714,6 +1714,11 @@ int s_server_main(int argc, char *argv[]) BIO_printf(bio_err, "Can only use -listen with DTLS\n"); goto end; } + + if (rev && socket_type == SOCK_DGRAM) { + BIO_printf(bio_err, "Can't use -rev with DTLS\n"); + goto end; + } #endif if (tfo && socket_type != SOCK_STREAM) { From 8aa3781bfc7f21b9add1f7ad3f25c78670ec182a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 11 Jan 2024 15:52:35 +0000 Subject: [PATCH 77/81] Move discovery of the legacy alg type into the keymgmt During creation of the EVP_PKEY_CTX we were trying to discover what legacy alg it corresponds to every time which was slow. Instead we move this into the construction of the EVP_KEYMGMT. Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23265) --- crypto/evp/evp_local.h | 2 ++ crypto/evp/keymgmt_meth.c | 29 +++++++++++++++++++++++++++++ crypto/evp/pmeth_lib.c | 20 +------------------- include/crypto/evp.h | 1 + 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index 9e4059d703797..35c302ff7b627 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -95,6 +95,8 @@ struct evp_keymgmt_st { int id; /* libcrypto internal */ int name_id; + /* NID for the legacy alg if there is one */ + int legacy_alg; char *type_name; const char *description; OSSL_PROVIDER *prov; diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c index 1d7031f33c824..f8f74925f8fbb 100644 --- a/crypto/evp/keymgmt_meth.c +++ b/crypto/evp/keymgmt_meth.c @@ -30,6 +30,26 @@ static void *keymgmt_new(void) return keymgmt; } +#ifndef FIPS_MODULE +static void help_get_legacy_alg_type_from_keymgmt(const char *keytype, + void *arg) +{ + int *type = arg; + + if (*type == NID_undef) + *type = evp_pkey_name2type(keytype); +} + +static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt) +{ + int type = NID_undef; + + EVP_KEYMGMT_names_do_all(keymgmt, help_get_legacy_alg_type_from_keymgmt, + &type); + return type; +} +#endif + static void *keymgmt_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov) @@ -218,6 +238,10 @@ static void *keymgmt_from_algorithm(int name_id, if (prov != NULL) ossl_provider_up_ref(prov); +#ifndef FIPS_MODULE + keymgmt->legacy_alg = get_legacy_alg_type_from_keymgmt(keymgmt); +#endif + return keymgmt; } @@ -275,6 +299,11 @@ int evp_keymgmt_get_number(const EVP_KEYMGMT *keymgmt) return keymgmt->name_id; } +int evp_keymgmt_get_legacy_alg(const EVP_KEYMGMT *keymgmt) +{ + return keymgmt->legacy_alg; +} + const char *EVP_KEYMGMT_get0_description(const EVP_KEYMGMT *keymgmt) { return keymgmt->description; diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 268b1617e3799..170f6ebcb0d02 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -133,24 +133,6 @@ EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags) pmeth->flags = flags | EVP_PKEY_FLAG_DYNAMIC; return pmeth; } - -static void help_get_legacy_alg_type_from_keymgmt(const char *keytype, - void *arg) -{ - int *type = arg; - - if (*type == NID_undef) - *type = evp_pkey_name2type(keytype); -} - -static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt) -{ - int type = NID_undef; - - EVP_KEYMGMT_names_do_all(keymgmt, help_get_legacy_alg_type_from_keymgmt, - &type); - return type; -} #endif /* FIPS_MODULE */ int evp_pkey_ctx_state(const EVP_PKEY_CTX *ctx) @@ -288,7 +270,7 @@ static EVP_PKEY_CTX *int_ctx_new(OSSL_LIB_CTX *libctx, * directly. */ if (keymgmt != NULL) { - int tmp_id = get_legacy_alg_type_from_keymgmt(keymgmt); + int tmp_id = evp_keymgmt_get_legacy_alg(keymgmt); if (tmp_id != NID_undef) { if (id == -1) { diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 96133bf7f59c6..5e05385d9f45e 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -951,6 +951,7 @@ int evp_kdf_get_number(const EVP_KDF *kdf); int evp_kem_get_number(const EVP_KEM *wrap); int evp_keyexch_get_number(const EVP_KEYEXCH *keyexch); int evp_keymgmt_get_number(const EVP_KEYMGMT *keymgmt); +int evp_keymgmt_get_legacy_alg(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); From afd8e29c360376420ea676581aa5d50b6027d069 Mon Sep 17 00:00:00 2001 From: Drokov Pavel Date: Fri, 12 Jan 2024 04:10:13 -0500 Subject: [PATCH 78/81] Remove receiving of unused return value CLA: trivial Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23277) --- apps/s_time.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/s_time.c b/apps/s_time.c index 1c6ed78b2cfd4..dd9f354be93e7 100644 --- a/apps/s_time.c +++ b/apps/s_time.c @@ -310,7 +310,6 @@ int s_time_main(int argc, char **argv) } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ - i = (int)((long)time(NULL) - finishtime + maxtime); printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); @@ -338,7 +337,7 @@ int s_time_main(int argc, char **argv) buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, www_path); if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) goto end; - while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) + while (SSL_read(scon, buf, sizeof(buf)) > 0) continue; } SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); From 5158d64e796275b35470d8081fc26c247f4da1c2 Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Thu, 11 Jan 2024 14:18:07 +0100 Subject: [PATCH 79/81] Support DTLS in TLS::Proxy. Fixes #23199 --- test/recipes/70-test_dtlsrecords.t | 153 ++++++++++++++++++ test/recipes/70-test_sslcbcpadding.t | 2 +- test/recipes/70-test_sslrecords.t | 13 +- test/recipes/70-test_tls13hrr.t | 3 +- util/perl/TLSProxy/Certificate.pm | 10 +- util/perl/TLSProxy/CertificateRequest.pm | 10 +- util/perl/TLSProxy/CertificateVerify.pm | 10 +- util/perl/TLSProxy/ClientHello.pm | 54 ++++++- util/perl/TLSProxy/EncryptedExtensions.pm | 10 +- util/perl/TLSProxy/HelloVerifyRequest.pm | 115 +++++++++++++ util/perl/TLSProxy/Message.pm | 187 ++++++++++++++++++---- util/perl/TLSProxy/NewSessionTicket.pm | 56 +++++++ util/perl/TLSProxy/Proxy.pm | 132 +++++++++++---- util/perl/TLSProxy/Record.pm | 184 +++++++++++++++++---- util/perl/TLSProxy/ServerHello.pm | 14 +- util/perl/TLSProxy/ServerKeyExchange.pm | 10 +- 16 files changed, 857 insertions(+), 106 deletions(-) create mode 100644 test/recipes/70-test_dtlsrecords.t create mode 100644 util/perl/TLSProxy/HelloVerifyRequest.pm diff --git a/test/recipes/70-test_dtlsrecords.t b/test/recipes/70-test_dtlsrecords.t new file mode 100644 index 0000000000000..99ce1128c0b31 --- /dev/null +++ b/test/recipes/70-test_dtlsrecords.t @@ -0,0 +1,153 @@ +#! /usr/bin/env perl +# Copyright 2024 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 feature 'state'; + +use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; +use OpenSSL::Test::Utils; +use TLSProxy::Proxy; +use TLSProxy::Message; + +my $test_name = "test_dtlsrecords"; +setup($test_name); + +plan skip_all => "TLSProxy isn't usable on $^O" + if $^O =~ /^(VMS)$/; + +plan skip_all => "$test_name needs the dynamic engine feature enabled" + if disabled("engine") || disabled("dynamic-engine"); + +plan skip_all => "$test_name needs the sock feature enabled" + if disabled("sock"); + +plan skip_all => "$test_name needs DTLSv1.2 enabled" + if disabled("dtls1_2"); + +my $proxy = TLSProxy::Proxy->new_dtls( + undef, + cmdstr(app(["openssl"]), display => 1), + srctop_file("apps", "server.pem"), + (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) +); + +plan tests => 4; + +my $fatal_alert = 0; # set by filters at expected fatal alerts +my $inject_recs_num = 0; # used by add_empty_recs_filter +my $proxy_start_success = 0; + +#Test 1: Injecting out of context empty records should succeed +my $content_type = TLSProxy::Record::RT_APPLICATION_DATA; +$inject_recs_num = 1; +$proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2"); +$proxy->clientflags("-max_protocol DTLSv1.2"); +$proxy->filter(\&add_empty_recs_filter); +$proxy_start_success = $proxy->start(); +ok($proxy_start_success && TLSProxy::Message->success(), "Out of context empty records test"); + +#Test 2: Injecting in context empty records should succeed +$proxy->clear(); +$content_type = TLSProxy::Record::RT_HANDSHAKE; +$inject_recs_num = 1; +$proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2"); +$proxy->clientflags("-max_protocol DTLSv1.2"); +$proxy->filter(\&add_empty_recs_filter); +$proxy_start_success = $proxy->start(); +ok($proxy_start_success && TLSProxy::Message->success(), "In context empty records test"); + +#Unrecognised record type tests + +#Test 3: Sending an unrecognised record type in DTLSv1.2 should fail +$fatal_alert = 0; +$proxy->clear(); +$proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2"); +$proxy->clientflags("-max_protocol DTLSv1.2"); +$proxy->filter(\&add_unknown_record_type); +ok($proxy->start() == 0, "Unrecognised record type in DTLS1.2"); + +SKIP: { + skip "DTLSv1 disabled", 1 if disabled("dtls1"); + + #Test 4: Sending an unrecognised record type in DTLSv1 should fail + $fatal_alert = 0; + $proxy->clear(); + $proxy->clientflags("-min_protocol DTLSv1 -max_protocol DTLSv1 -cipher DEFAULT:\@SECLEVEL=0"); + $proxy->ciphers("AES128-SHA:\@SECLEVEL=0"); + $proxy->filter(\&add_unknown_record_type); + ok($proxy->start() == 0, "Unrecognised record type in DTLSv1"); +} + +sub add_empty_recs_filter +{ + my $proxy = shift; + my $records = $proxy->record_list; + + # We're only interested in the initial ClientHello + if ($proxy->flight != 0) { + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; + return; + } + + for (my $i = 0; $i < $inject_recs_num; $i++) { + my $record = TLSProxy::Record->new_dtls( + 0, + $content_type, + TLSProxy::Record::VERS_TLS_1_2, + 0, + 0, + 0, + 0, + 0, + 0, + "", + "" + ); + push @{$records}, $record; + } +} + +sub add_unknown_record_type +{ + my $proxy = shift; + my $records = $proxy->record_list; + state $added_record; + + # We'll change a record after the initial version neg has taken place + if ($proxy->flight == 0) { + $added_record = 0; + return; + } elsif ($proxy->flight != 1 || $added_record) { + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; + return; + } + + my $record = TLSProxy::Record->new_dtls( + 1, + TLSProxy::Record::RT_UNKNOWN, + @{$records}[-1]->version(), + @{$records}[-1]->epoch(), + @{$records}[-1]->seq() +1, + 1, + 0, + 1, + 1, + "X", + "X" + ); + + #Find ServerHello record and insert after that + my $i; + for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) { + next; + } + $i++; + + splice @{$proxy->record_list}, $i, 0, $record; + $added_record = 1; +} diff --git a/test/recipes/70-test_sslcbcpadding.t b/test/recipes/70-test_sslcbcpadding.t index c24f315c60024..e49efb28e255b 100644 --- a/test/recipes/70-test_sslcbcpadding.t +++ b/test/recipes/70-test_sslcbcpadding.t @@ -127,6 +127,6 @@ sub add_maximal_padding_filter } elsif ($sent_corrupted_payload) { # Check for bad_record_mac from client my $last_record = @{$proxy->record_list}[-1]; - $fatal_alert = 1 if $last_record->is_fatal_alert(0) == 20; + $fatal_alert = 1 if $last_record->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_BAD_RECORD_MAC; } } diff --git a/test/recipes/70-test_sslrecords.t b/test/recipes/70-test_sslrecords.t index 9a7e3d8c06839..43e288b63e564 100644 --- a/test/recipes/70-test_sslrecords.t +++ b/test/recipes/70-test_sslrecords.t @@ -12,6 +12,7 @@ use feature 'state'; use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; use OpenSSL::Test::Utils; use TLSProxy::Proxy; +use TLSProxy::Message; my $test_name = "test_sslrecords"; setup($test_name); @@ -273,7 +274,7 @@ sub add_empty_recs_filter # We're only interested in the initial ClientHello if ($proxy->flight != 0) { - $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10; + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; return; } @@ -301,7 +302,7 @@ sub add_frag_alert_filter # We're only interested in the initial ClientHello if ($proxy->flight != 0) { - $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10; + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; return; } @@ -507,7 +508,7 @@ sub add_unknown_record_type $added_record = 0; return; } elsif ($proxy->flight != 1 || $added_record) { - $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10; + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; return; } @@ -541,7 +542,7 @@ sub change_version # We'll change a version after the initial version neg has taken place if ($proxy->flight != 1) { - $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70; + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_PROTOCOL_VERSION; return; } @@ -578,7 +579,7 @@ sub change_outer_record_type # We'll change a record after the initial version neg has taken place if ($proxy->flight != 1) { - $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10; + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; return; } @@ -601,7 +602,7 @@ sub not_on_record_boundary #Find server's first flight if ($proxy->flight != 1) { - $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10; + $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; return; } diff --git a/test/recipes/70-test_tls13hrr.t b/test/recipes/70-test_tls13hrr.t index 3feabef060ce7..c49a6be88bd94 100644 --- a/test/recipes/70-test_tls13hrr.t +++ b/test/recipes/70-test_tls13hrr.t @@ -10,6 +10,7 @@ use strict; use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; use OpenSSL::Test::Utils; use TLSProxy::Proxy; +use TLSProxy::Message; my $test_name = "test_tls13hrr"; setup($test_name); @@ -122,7 +123,7 @@ sub hrr_filter # and the unexpected_message alert from client if ($proxy->flight == 4) { $fatal_alert = 1 - if @{$proxy->record_list}[-1]->is_fatal_alert(0) == 10; + if @{$proxy->record_list}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE; return; } if ($proxy->flight != 3) { diff --git a/util/perl/TLSProxy/Certificate.pm b/util/perl/TLSProxy/Certificate.pm index 03f661995482e..a32bc2c97b7da 100644 --- a/util/perl/TLSProxy/Certificate.pm +++ b/util/perl/TLSProxy/Certificate.pm @@ -15,15 +15,23 @@ push @ISA, 'TLSProxy::Message'; sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_CERTIFICATE, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, diff --git a/util/perl/TLSProxy/CertificateRequest.pm b/util/perl/TLSProxy/CertificateRequest.pm index 193bea168a532..0191df68f9fbf 100644 --- a/util/perl/TLSProxy/CertificateRequest.pm +++ b/util/perl/TLSProxy/CertificateRequest.pm @@ -15,15 +15,23 @@ push @ISA, 'TLSProxy::Message'; sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_CERTIFICATE_REQUEST, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, diff --git a/util/perl/TLSProxy/CertificateVerify.pm b/util/perl/TLSProxy/CertificateVerify.pm index fe45001405028..95922729918c5 100644 --- a/util/perl/TLSProxy/CertificateVerify.pm +++ b/util/perl/TLSProxy/CertificateVerify.pm @@ -15,15 +15,23 @@ push @ISA, 'TLSProxy::Message'; sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_CERTIFICATE_VERIFY, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, diff --git a/util/perl/TLSProxy/ClientHello.pm b/util/perl/TLSProxy/ClientHello.pm index c49bc23671ffd..5a5f5fd34da60 100644 --- a/util/perl/TLSProxy/ClientHello.pm +++ b/util/perl/TLSProxy/ClientHello.pm @@ -9,30 +9,43 @@ use strict; package TLSProxy::ClientHello; +use TLSProxy::Record; + use vars '@ISA'; push @ISA, 'TLSProxy::Message'; sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, - 1, + TLSProxy::Message::MT_CLIENT_HELLO, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens); + $self->{isdtls} = $isdtls; $self->{client_version} = 0; $self->{random} = []; $self->{session_id_len} = 0; $self->{session} = ""; + $self->{legacy_cookie_len} = 0; #DTLS only + $self->{legacy_cookie} = ""; #DTLS only $self->{ciphersuite_len} = 0; $self->{ciphersuites} = []; $self->{comp_meth_len} = 0; @@ -54,6 +67,14 @@ sub parse $ptr++; my $session = substr($self->data, $ptr, $session_id_len); $ptr += $session_id_len; + my $legacy_cookie_len = 0; + my $legacy_cookie = ""; + if($self->{isdtls}) { + $legacy_cookie_len = unpack('C', substr($self->data, $ptr)); + $ptr++; + $legacy_cookie = substr($self->data, $ptr, $legacy_cookie_len); + $ptr += $legacy_cookie_len; + } my $ciphersuite_len = unpack('n', substr($self->data, $ptr)); $ptr += 2; my @ciphersuites = unpack('n*', substr($self->data, $ptr, @@ -84,6 +105,8 @@ sub parse $self->random($random); $self->session_id_len($session_id_len); $self->session($session); + $self->legacy_cookie_len($legacy_cookie_len); + $self->legacy_cookie($legacy_cookie); $self->ciphersuite_len($ciphersuite_len); $self->ciphersuites(\@ciphersuites); $self->comp_meth_len($comp_meth_len); @@ -93,8 +116,11 @@ sub parse $self->process_extensions(); - print " Client Version:".$client_version."\n"; + print " Client Version:".$TLSProxy::Record::tls_version{$client_version}."\n"; print " Session ID Len:".$session_id_len."\n"; + if($self->{isdtls}) { + print " Legacy Cookie Len:".$legacy_cookie_len."\n"; + } print " Ciphersuite len:".$ciphersuite_len."\n"; print " Compression Method Len:".$comp_meth_len."\n"; print " Extensions Len:".$extensions_len."\n"; @@ -138,6 +164,12 @@ sub set_message_contents $data .= $self->random; $data .= pack('C', $self->session_id_len); $data .= $self->session; + if($self->{isdtls}){ + $data .= pack('C', $self->legacy_cookie_len); + if($self->legacy_cookie_len > 0) { + $data .= $self->legacy_cookie; + } + } $data .= pack('n', $self->ciphersuite_len); $data .= pack("n*", @{$self->ciphersuites}); $data .= pack('C', $self->comp_meth_len); @@ -197,6 +229,22 @@ sub session } return $self->{session}; } +sub legacy_cookie_len +{ + my $self = shift; + if (@_) { + $self->{legacy_cookie_len} = shift; + } + return $self->{legacy_cookie_len}; +} +sub legacy_cookie +{ + my $self = shift; + if (@_) { + $self->{legacy_cookie} = shift; + } + return $self->{legacy_cookie}; +} sub ciphersuite_len { my $self = shift; diff --git a/util/perl/TLSProxy/EncryptedExtensions.pm b/util/perl/TLSProxy/EncryptedExtensions.pm index 4fd445b41e08c..5f867101d9f49 100644 --- a/util/perl/TLSProxy/EncryptedExtensions.pm +++ b/util/perl/TLSProxy/EncryptedExtensions.pm @@ -15,15 +15,23 @@ push @ISA, 'TLSProxy::Message'; sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, diff --git a/util/perl/TLSProxy/HelloVerifyRequest.pm b/util/perl/TLSProxy/HelloVerifyRequest.pm new file mode 100644 index 0000000000000..40162d08ef63e --- /dev/null +++ b/util/perl/TLSProxy/HelloVerifyRequest.pm @@ -0,0 +1,115 @@ +# Copyright 2016-2018 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; + +package TLSProxy::HelloVerifyRequest; + +use TLSProxy::Record; + +use vars '@ISA'; +push @ISA, 'TLSProxy::Message'; + + +sub new +{ + my $class = shift; + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens) = @_; + + my $self = $class->SUPER::new( + $isdtls, + $server, + TLSProxy::Message::MT_HELLO_VERIFY_REQUEST, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens); + + $self->{server_version} = 0; + $self->{cookie_len} = 0; + $self->{cookie} = ""; + + return $self; +} + +sub parse +{ + my $self = shift; + + my ($server_version) = unpack('n', $self->data); + my $ptr = 2; + my $cookie_len = unpack('C', substr($self->data, $ptr)); + $ptr++; + my $cookie = substr($self->data, $ptr, $cookie_len); + + $self->server_version($server_version); + $self->cookie_len($cookie_len); + $self->cookie($cookie); + + $self->process_data(); + + print " Server Version:".$TLSProxy::Record::tls_version{$server_version}."\n"; + print " Cookie Len:".$cookie_len."\n"; +} + +#Perform any actions necessary based on the data we've seen +sub process_data +{ + my $self = shift; + #Intentional no-op +} + +#Reconstruct the on-the-wire message data following changes +sub set_message_contents +{ + my $self = shift; + my $data; + + $data = pack('n', $self->server_version); + $data .= pack('C', $self->cookie_len); + $data .= $self->cookie; + + $self->data($data); +} + +#Read/write accessors +sub server_version +{ + my $self = shift; + if (@_) { + $self->{server_version} = shift; + } + return $self->{server_version}; +} +sub cookie_len +{ + my $self = shift; + if (@_) { + $self->{cookie_len} = shift; + } + return $self->{cookie_len}; +} +sub cookie +{ + my $self = shift; + if (@_) { + $self->{cookie} = shift; + } + return $self->{cookie}; +} +1; diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm index ce221875697f1..c5e822e90d3d8 100644 --- a/util/perl/TLSProxy/Message.pm +++ b/util/perl/TLSProxy/Message.pm @@ -11,6 +11,7 @@ package TLSProxy::Message; use TLSProxy::Alert; +use constant DTLS_MESSAGE_HEADER_LENGTH => 12; use constant TLS_MESSAGE_HEADER_LENGTH => 4; #Message types @@ -18,6 +19,7 @@ use constant { MT_HELLO_REQUEST => 0, MT_CLIENT_HELLO => 1, MT_SERVER_HELLO => 2, + MT_HELLO_VERIFY_REQUEST => 3, MT_NEW_SESSION_TICKET => 4, MT_ENCRYPTED_EXTENSIONS => 8, MT_CERTIFICATE => 11, @@ -42,7 +44,9 @@ use constant { use constant { AL_DESC_CLOSE_NOTIFY => 0, AL_DESC_UNEXPECTED_MESSAGE => 10, + AL_DESC_BAD_RECORD_MAC => 20, AL_DESC_ILLEGAL_PARAMETER => 47, + AL_DESC_PROTOCOL_VERSION => 70, AL_DESC_NO_RENEGOTIATION => 100 }; @@ -50,6 +54,7 @@ my %message_type = ( MT_HELLO_REQUEST, "HelloRequest", MT_CLIENT_HELLO, "ClientHello", MT_SERVER_HELLO, "ServerHello", + MT_HELLO_VERIFY_REQUEST, "HelloVerifyRequest", MT_NEW_SESSION_TICKET, "NewSessionTicket", MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions", MT_CERTIFICATE, "Certificate", @@ -172,6 +177,7 @@ sub get_messages my $class = shift; my $serverin = shift; my $record = shift; + my $isdtls = shift; my @messages = (); my $message; @@ -216,8 +222,14 @@ sub get_messages $recoffset = $messlen - length($payload); $payload .= substr($record->decrypt_data, 0, $recoffset); push @message_frag_lens, $recoffset; - $message = create_message($server, $mt, $payload, - $startoffset); + if ($isdtls) { + # We must set $msgseq, $msgfrag, $msgfragoffs + die "Internal error: cannot handle partial dtls messages\n" + } + $message = create_message($server, $mt, + #$msgseq, $msgfrag, $msgfragoffs, + 0, 0, 0, + $payload, $startoffset, $isdtls); push @messages, $message; $payload = ""; @@ -232,21 +244,36 @@ sub get_messages while ($record->decrypt_len > $recoffset) { #We are at the start of a new message - if ($record->decrypt_len - $recoffset < 4) { + my $msgheaderlen = $isdtls ? DTLS_MESSAGE_HEADER_LENGTH + : TLS_MESSAGE_HEADER_LENGTH; + if ($record->decrypt_len - $recoffset < $msgheaderlen) { #Whilst technically probably valid we can't cope with this die "End of record in the middle of a message header\n"; } @message_rec_list = ($record); my $lenhi; my $lenlo; - ($mt, $lenhi, $lenlo) = unpack('CnC', - substr($record->decrypt_data, - $recoffset)); + my $msgseq; + my $msgfrag; + my $msgfragoffs; + if ($isdtls) { + my $msgfraghi; + my $msgfraglo; + my $msgfragoffshi; + my $msgfragoffslo; + ($mt, $lenhi, $lenlo, $msgseq, $msgfraghi, $msgfraglo, $msgfragoffshi, $msgfragoffslo) = + unpack('CnCnnCnC', substr($record->decrypt_data, $recoffset)); + $msgfrag = ($msgfraghi << 8) | $msgfraglo; + $msgfragoffs = ($msgfragoffshi << 8) | $msgfragoffslo; + } else { + ($mt, $lenhi, $lenlo) = + unpack('CnC', substr($record->decrypt_data, $recoffset)); + } $messlen = ($lenhi << 8) | $lenlo; - print " Message type: $message_type{$mt}\n"; + print " Message type: $message_type{$mt}($mt)\n"; print " Message Length: $messlen\n"; $startoffset = $recoffset; - $recoffset += 4; + $recoffset += $msgheaderlen; $payload = ""; if ($recoffset <= $record->decrypt_len) { @@ -257,8 +284,9 @@ sub get_messages $messlen); $recoffset += $messlen; push @message_frag_lens, $messlen; - $message = create_message($server, $mt, $payload, - $startoffset); + $message = create_message($server, $mt, $msgseq, + $msgfrag, $msgfragoffs, + $payload, $startoffset, $isdtls); push @messages, $message; $payload = ""; @@ -307,14 +335,18 @@ sub get_messages #construct it sub create_message { - my ($server, $mt, $data, $startoffset) = @_; + my ($server, $mt, $msgseq, $msgfrag, $msgfragoffs, $data, $startoffset, $isdtls) = @_; my $message; #We only support ClientHello in this version...needs to be extended for #others if ($mt == MT_CLIENT_HELLO) { $message = TLSProxy::ClientHello->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -323,7 +355,24 @@ sub create_message $message->parse(); } elsif ($mt == MT_SERVER_HELLO) { $message = TLSProxy::ServerHello->new( + $isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + $message->parse(); + } elsif ($mt == MT_HELLO_VERIFY_REQUEST) { + $message = TLSProxy::HelloVerifyRequest->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -332,7 +381,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) { $message = TLSProxy::EncryptedExtensions->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -341,7 +394,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_CERTIFICATE) { $message = TLSProxy::Certificate->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -350,7 +407,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_CERTIFICATE_REQUEST) { $message = TLSProxy::CertificateRequest->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -359,7 +420,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_CERTIFICATE_VERIFY) { $message = TLSProxy::CertificateVerify->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -368,7 +433,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_SERVER_KEY_EXCHANGE) { $message = TLSProxy::ServerKeyExchange->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -376,19 +445,36 @@ sub create_message ); $message->parse(); } elsif ($mt == MT_NEW_SESSION_TICKET) { - $message = TLSProxy::NewSessionTicket->new( - $server, - $data, - [@message_rec_list], - $startoffset, - [@message_frag_lens] - ); + if ($isdtls) { + $message = TLSProxy::NewSessionTicket->new_dtls( + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + } else { + $message = TLSProxy::NewSessionTicket->new( + $server, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + } $message->parse(); } else { #Unknown message type $message = TLSProxy::Message->new( + $isdtls, $server, $mt, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -423,18 +509,26 @@ sub alert sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, $mt, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = { + isdtls => $isdtls, server => $server, data => $data, records => $records, mt => $mt, + msgseq => $msgseq, + msgfrag => $msgfrag, + msgfragoffs => $msgfragoffs, startoffset => $startoffset, message_frag_lens => $message_frag_lens, dupext => -1 @@ -463,12 +557,21 @@ sub repack $self->set_message_contents(); - my $lenhi; - my $lenlo; + my $lenlo = length($self->data) & 0xff; + my $lenhi = length($self->data) >> 8; - $lenlo = length($self->data) & 0xff; - $lenhi = length($self->data) >> 8; - $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; + if ($self->{isdtls}) { + my $msgfraghi = $self->msgfrag >> 8; + my $msgfraglo = $self->msgfrag & 0xff; + my $msgfragoffshi = $self->msgfragoffs >> 8; + my $msgfragoffslo = $self->msgfragoffs & 0xff; + + $msgdata = pack('CnCnnCnC', $self->mt, $lenhi, $lenlo, $self->msgseq, + $msgfraghi, $msgfraglo, + $msgfragoffshi, $msgfragoffslo).$self->data; + } else { + $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; + } if ($numrecs == 0) { #The message is fully contained within one record @@ -476,13 +579,14 @@ sub repack my $recdata = $rec->decrypt_data; my $old_length; + my $msg_header_len = $self->{isdtls} ? DTLS_MESSAGE_HEADER_LENGTH + : TLS_MESSAGE_HEADER_LENGTH; # We use empty message_frag_lens to indicates that pre-repacking, # the message wasn't present. The first fragment length doesn't include # the TLS header, so we need to check and compute the right length. if (@{$self->message_frag_lens}) { - $old_length = ${$self->message_frag_lens}[0] + - TLS_MESSAGE_HEADER_LENGTH; + $old_length = ${$self->message_frag_lens}[0] + $msg_header_len; } else { $old_length = 0; } @@ -529,8 +633,7 @@ sub repack $rec->len(length($rec->data)); #Update the fragment len in case we changed it above - ${$self->message_frag_lens}[0] = length($msgdata) - - TLS_MESSAGE_HEADER_LENGTH; + ${$self->message_frag_lens}[0] = length($msgdata) - $msg_header_len; return; } @@ -578,6 +681,30 @@ sub mt } return $self->{mt}; } +sub msgseq +{ + my $self = shift; + if (@_) { + $self->{msgseq} = shift; + } + return $self->{msgseq}; +} +sub msgfrag +{ + my $self = shift; + if (@_) { + $self->{msgfrag} = shift; + } + return $self->{msgfrag}; +} +sub msgfragoffs +{ + my $self = shift; + if (@_) { + $self->{msgfragoffs} = shift; + } + return $self->{msgfragoffs}; +} sub data { my $self = shift; @@ -613,7 +740,9 @@ sub message_frag_lens sub encoded_length { my $self = shift; - return TLS_MESSAGE_HEADER_LENGTH + length($self->data); + my $msg_header_len = $self->{isdtls} ? DTLS_MESSAGE_HEADER_LENGTH + : TLS_MESSAGE_HEADER_LENGTH; + return $msg_header_len + length($self->data); } sub dupext { diff --git a/util/perl/TLSProxy/NewSessionTicket.pm b/util/perl/TLSProxy/NewSessionTicket.pm index 1c532ff7beef5..748efb8aa8f56 100644 --- a/util/perl/TLSProxy/NewSessionTicket.pm +++ b/util/perl/TLSProxy/NewSessionTicket.pm @@ -12,18 +12,74 @@ package TLSProxy::NewSessionTicket; use vars '@ISA'; push @ISA, 'TLSProxy::Message'; +sub new_dtls +{ + my $class = shift; + + my ($server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens) = @_; + + return $class->init( + 1, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens + ) +} + sub new { my $class = shift; + my ($server, $data, $records, $startoffset, $message_frag_lens) = @_; + return $class->init( + 0, + $server, + 0, # msgseq + 0, # msgfrag + 0, # $msgfragoffs + $data, + $records, + $startoffset, + $message_frag_lens + ) +} + +sub init{ + my $class = shift; + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens) = @_; + my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_NEW_SESSION_TICKET, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm index 3de10eccb94ef..0084328a5f17a 100644 --- a/util/perl/TLSProxy/Proxy.pm +++ b/util/perl/TLSProxy/Proxy.pm @@ -17,6 +17,7 @@ use TLSProxy::Record; use TLSProxy::Message; use TLSProxy::ClientHello; use TLSProxy::ServerHello; +use TLSProxy::HelloVerifyRequest; use TLSProxy::EncryptedExtensions; use TLSProxy::Certificate; use TLSProxy::CertificateRequest; @@ -71,17 +72,37 @@ BEGIN my $is_tls13 = 0; my $ciphersuite = undef; -sub new -{ +sub new { + my $class = shift; + my ($filter, + $execute, + $cert, + $debug) = @_; + return init($class, $filter, $execute, $cert, $debug, 0); +} + +sub new_dtls { my $class = shift; my ($filter, $execute, $cert, $debug) = @_; + return init($class, $filter, $execute, $cert, $debug, 1); +} + +sub init +{ + my $class = shift; + my ($filter, + $execute, + $cert, + $debug, + $isdtls) = @_; my $self = { #Public read/write proxy_addr => $have_IPv6 ? "[::1]" : "127.0.0.1", + client_addr => $have_IPv6 ? "[::1]" : "127.0.0.1", filter => $filter, serverflags => "", clientflags => "", @@ -90,7 +111,9 @@ sub new sessionfile => undef, #Public read + isdtls => $isdtls, proxy_port => 0, + client_port => 49152 + int(rand(65535 - 49152)), server_port => 0, serverpid => 0, clientpid => 0, @@ -108,29 +131,6 @@ sub new message_list => [], }; - # Create the Proxy socket - my $proxaddr = $self->{proxy_addr}; - $proxaddr =~ s/[\[\]]//g; # Remove [ and ] - my @proxyargs = ( - LocalHost => $proxaddr, - LocalPort => 0, - Proto => "tcp", - Listen => SOMAXCONN, - ); - - if (my $sock = $IP_factory->(@proxyargs)) { - $self->{proxy_sock} = $sock; - $self->{proxy_port} = $sock->sockport(); - $self->{proxy_addr} = $sock->sockhost(); - $self->{proxy_addr} =~ s/(.*:.*)/[$1]/; - print "Proxy started on port ", - "$self->{proxy_addr}:$self->{proxy_port}\n"; - # use same address for s_server - $self->{server_addr} = $self->{proxy_addr}; - } else { - warn "Failed creating proxy socket (".$proxaddr.",0): $!\n"; - } - return bless $self, $class; } @@ -200,7 +200,7 @@ sub connect_to_server my $sock = $IP_factory->(PeerAddr => $servaddr, PeerPort => $self->{server_port}, - Proto => 'tcp'); + Proto => $self->{isdtls} ? 'udp' : 'tcp'); if (!defined($sock)) { my $err = $!; kill(3, $self->{real_serverpid}); @@ -215,12 +215,51 @@ sub start my ($self) = shift; my $pid; + + # Create the Proxy socket + my $proxaddr = $self->{proxy_addr}; + $proxaddr =~ s/[\[\]]//g; # Remove [ and ] + my $clientaddr = $self->{client_addr}; + $clientaddr =~ s/[\[\]]//g; # Remove [ and ] + + my @proxyargs; + + if ($self->{isdtls}) { + @proxyargs = ( + LocalHost => $proxaddr, + LocalPort => 0, + PeerHost => $clientaddr, + PeerPort => $self->{client_port}, + Proto => "udp", + ); + } else { + @proxyargs = ( + LocalHost => $proxaddr, + LocalPort => 0, + Proto => "tcp", + Listen => SOMAXCONN, + ); + } + + if (my $sock = $IP_factory->(@proxyargs)) { + $self->{proxy_sock} = $sock; + $self->{proxy_port} = $sock->sockport(); + $self->{proxy_addr} = $sock->sockhost(); + $self->{proxy_addr} =~ s/(.*:.*)/[$1]/; + print "Proxy started on port ", + "$self->{proxy_addr}:$self->{proxy_port}\n"; + # use same address for s_server + $self->{server_addr} = $self->{proxy_addr}; + } else { + warn "Failed creating proxy socket (".$proxaddr.",0): $!\n"; + } + if ($self->{proxy_sock} == 0) { return 0; } my $execcmd = $self->execute - ." s_server -max_protocol TLSv1.3 -no_comp -rev -engine ossltest" + ." s_server -no_comp -engine ossltest -state" #In TLSv1.3 we issue two session tickets. The default session id #callback gets confused because the ossltest engine causes the same #session id to be created twice due to the changed random number @@ -230,6 +269,14 @@ sub start ." -accept $self->{server_addr}:0" ." -cert ".$self->cert." -cert2 ".$self->cert ." -naccept ".$self->serverconnects; + if ($self->{isdtls}) { + $execcmd .= " -dtls -max_protocol DTLSv1.2" + # TLSProxy does not support message fragmentation. So + # set a high mtu and fingers crossed. + ." -mtu 1500"; + } else { + $execcmd .= " -rev -max_protocol TLSv1.3"; + } if ($self->ciphers ne "") { $execcmd .= " -cipher ".$self->ciphers; } @@ -311,11 +358,24 @@ sub clientstart { my ($self) = shift; + my $succes = 1; + if ($self->execute) { my $pid; my $execcmd = $self->execute - ." s_client -max_protocol TLSv1.3 -engine ossltest" + ." s_client -engine ossltest" ." -connect $self->{proxy_addr}:$self->{proxy_port}"; + if ($self->{isdtls}) { + $execcmd .= " -dtls -max_protocol DTLSv1.2" + # TLSProxy does not support message fragmentation. So + # set a high mtu and fingers crossed. + ." -mtu 1500" + # UDP has no "accept" for sockets which means we need to + # know were to send data back to. + ." -bind $self->{client_addr}:$self->{client_port}"; + } else { + $execcmd .= " -max_protocol TLSv1.3"; + } if ($self->cipherc ne "") { $execcmd .= " -cipher ".$self->cipherc; } @@ -362,7 +422,9 @@ sub clientstart } my $client_sock; - if(!($client_sock = $self->{proxy_sock}->accept())) { + if($self->{isdtls}) { + $client_sock = $self->{proxy_sock} + } elsif (!($client_sock = $self->{proxy_sock}->accept())) { warn "Failed accepting incoming connection: $!\n"; return 0; } @@ -386,6 +448,9 @@ sub clientstart && $self->{saw_session_ticket}; } if (!(@ready = $fdset->can_read(1))) { + last if TLSProxy::Message->success() + && $self->{saw_session_ticket}; + $ctr++; next; } @@ -419,7 +484,8 @@ sub clientstart if ($ctr >= 10) { kill(3, $self->{real_serverpid}); - die "No progress made"; + print "No progress made\n"; + $succes = 0; } END: @@ -460,7 +526,7 @@ sub clientstart print "Waiting for s_client process to close: $pid...\n"; waitpid($pid, 0); - return 1; + return $succes; } sub process_packet @@ -488,7 +554,9 @@ sub process_packet #Return contains the list of record found in the packet followed by the #list of messages in those records and any partial message my @ret = TLSProxy::Record->get_records($server, $self->flight, - $self->{partial}[$server].$packet); + $self->{partial}[$server].$packet, + $self->{isdtls}); + $self->{partial}[$server] = $ret[2]; push @{$self->{record_list}}, @{$ret[0]}; push @{$self->{message_list}}, @{$ret[1]}; diff --git a/util/perl/TLSProxy/Record.pm b/util/perl/TLSProxy/Record.pm index 183aa0569798d..c309bc2f9fb6d 100644 --- a/util/perl/TLSProxy/Record.pm +++ b/util/perl/TLSProxy/Record.pm @@ -15,6 +15,7 @@ my $server_encrypting = 0; my $client_encrypting = 0; my $etm = 0; +use constant DTLS_RECORD_HEADER_LENGTH => 13; use constant TLS_RECORD_HEADER_LENGTH => 5; #Record types @@ -35,6 +36,8 @@ my %record_type = ( ); use constant { + VERS_DTLS_1_2 => 0xfefd, + VERS_DTLS_1 => 0xfeff, VERS_TLS_1_4 => 0x0305, VERS_TLS_1_3 => 0x0304, VERS_TLS_1_2 => 0x0303, @@ -44,7 +47,9 @@ use constant { VERS_SSL_LT_3_0 => 0x02ff }; -my %tls_version = ( +our %tls_version = ( + VERS_DTLS_1_2, "DTLS1.2", + VERS_DTLS_1, "DTLS1", VERS_TLS_1_3, "TLS1.3", VERS_TLS_1_2, "TLS1.2", VERS_TLS_1_1, "TLS1.1", @@ -60,41 +65,81 @@ sub get_records my $server = shift; my $flight = shift; my $packet = shift; + my $isdtls = shift; my $partial = ""; my @record_list = (); my @message_list = (); + my $record_hdr_len = $isdtls ? DTLS_RECORD_HEADER_LENGTH + : TLS_RECORD_HEADER_LENGTH; my $recnum = 1; while (length ($packet) > 0) { print " Record $recnum ", $server ? "(server -> client)\n" : "(client -> server)\n"; - #Get the record header (unpack can't fail if $packet is too short) - my ($content_type, $version, $len) = unpack('Cnn', $packet); + my $content_type; + my $version; + my $len; + my $epoch; + my $seq; + + if ($isdtls) { + my $seqhi; + my $seqmi; + my $seqlo; + #Get the record header (unpack can't fail if $packet is too short) + ($content_type, $version, $epoch, + $seqhi, $seqmi, $seqlo, $len) = unpack('Cnnnnnn', $packet); + $seq = ($seqhi << 32) | ($seqmi << 16) | $seqlo + } else { + #Get the record header (unpack can't fail if $packet is too short) + ($content_type, $version, $len) = unpack('Cnn', $packet); + } - if (length($packet) < TLS_RECORD_HEADER_LENGTH + ($len // 0)) { + if (length($packet) < $record_hdr_len + ($len // 0)) { print "Partial data : ".length($packet)." bytes\n"; $partial = $packet; last; } - my $data = substr($packet, TLS_RECORD_HEADER_LENGTH, $len); + my $data = substr($packet, $record_hdr_len, $len); print " Content type: ".$record_type{$content_type}."\n"; print " Version: $tls_version{$version}\n"; + if($isdtls) { + print " Epoch: $epoch\n"; + print " Sequence: $seq\n"; + } print " Length: $len\n"; - my $record = TLSProxy::Record->new( - $flight, - $content_type, - $version, - $len, - 0, - $len, # len_real - $len, # decrypt_len - $data, # data - $data # decrypt_data - ); + my $record; + if ($isdtls) { + $record = TLSProxy::Record->new_dtls( + $flight, + $content_type, + $version, + $epoch, + $seq, + $len, + 0, + $len, # len_real + $len, # decrypt_len + $data, # data + $data # decrypt_data + ); + } else { + $record = TLSProxy::Record->new( + $flight, + $content_type, + $version, + $len, + 0, + $len, # len_real + $len, # decrypt_len + $data, # data + $data # decrypt_data + ); + } if ($content_type != RT_CCS && (!TLSProxy::Proxy->is_tls13() @@ -118,10 +163,10 @@ sub get_records push @record_list, $record; #Now figure out what messages are contained within this record - my @messages = TLSProxy::Message->get_messages($server, $record); + my @messages = TLSProxy::Message->get_messages($server, $record, $isdtls); push @message_list, @messages; - $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len); + $packet = substr($packet, $record_hdr_len + $len); $recnum++; } @@ -161,6 +206,34 @@ sub etm return $etm; } +sub new_dtls +{ + my $class = shift; + my ($flight, + $content_type, + $version, + $epoch, + $seq, + $len, + $sslv2, + $len_real, + $decrypt_len, + $data, + $decrypt_data) = @_; + return $class->init(1, + $flight, + $content_type, + $version, + $epoch, + $seq, + $len, + $sslv2, + $len_real, + $decrypt_len, + $data, + $decrypt_data); +} + sub new { my $class = shift; @@ -173,11 +246,44 @@ sub new $decrypt_len, $data, $decrypt_data) = @_; + return $class->init( + 0, + $flight, + $content_type, + $version, + 0, #epoch + 0, #seq + $len, + $sslv2, + $len_real, + $decrypt_len, + $data, + $decrypt_data); +} + +sub init +{ + my $class = shift; + my ($isdtls, + $flight, + $content_type, + $version, + $epoch, + $seq, + $len, + $sslv2, + $len_real, + $decrypt_len, + $data, + $decrypt_data) = @_; my $self = { + isdtls => $isdtls, flight => $flight, content_type => $content_type, version => $version, + epoch => $epoch, + seq => $seq, len => $len, sslv2 => $sslv2, len_real => $len_real, @@ -285,12 +391,21 @@ sub reconstruct_record if ($self->sslv2) { $data = pack('n', $self->len | 0x8000); } else { - if (TLSProxy::Proxy->is_tls13() && $self->encrypted) { - $data = pack('Cnn', $self->outer_content_type, $self->version, - $self->len); + if($self->{isdtls}) { + my $seqhi = ($self->seq >> 32) & 0xffff; + my $seqmi = ($self->seq >> 16) & 0xffff; + my $seqlo = ($self->seq >> 0) & 0xffff; + $data = pack('Cnnnnnn', $self->content_type, $self->version, + $self->epoch, $seqhi, $seqmi, $seqlo, $self->len); } else { - $data = pack('Cnn', $self->content_type, $self->version, - $self->len); + if (TLSProxy::Proxy->is_tls13() && $self->encrypted) { + $data = pack('Cnn', $self->outer_content_type, $self->version, + $self->len); + } + else { + $data = pack('Cnn', $self->content_type, $self->version, + $self->len); + } } } @@ -370,6 +485,22 @@ sub content_type } return $self->{content_type}; } +sub epoch +{ + my $self = shift; + if (@_) { + $self->{epoch} = shift; + } + return $self->{epoch}; +} +sub seq +{ + my $self = shift; + if (@_) { + $self->{seq} = shift; + } + return $self->{seq}; +} sub encrypted { my $self = shift; @@ -391,10 +522,9 @@ sub is_fatal_alert my $self = shift; my $server = shift; - if (($self->{flight} & 1) == $server - && $self->{content_type} == TLSProxy::Record::RT_ALERT) { - my ($level, $alert) = unpack('CC', $self->decrypt_data); - return $alert if ($level == 2); + if (($self->{flight} & 1) == $server && $self->{content_type} == RT_ALERT) { + my ($level, $description) = unpack('CC', $self->decrypt_data); + return $description if ($level == 2); } return 0; } diff --git a/util/perl/TLSProxy/ServerHello.pm b/util/perl/TLSProxy/ServerHello.pm index ab7f2c8f8ab0e..ca1486e0411de 100644 --- a/util/perl/TLSProxy/ServerHello.pm +++ b/util/perl/TLSProxy/ServerHello.pm @@ -9,6 +9,8 @@ use strict; package TLSProxy::ServerHello; +use TLSProxy::Record; + use vars '@ISA'; push @ISA, 'TLSProxy::Message'; @@ -20,15 +22,23 @@ my $hrrrandom = pack("C*", 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_SERVER_HELLO, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, @@ -120,7 +130,7 @@ sub parse $self->process_data(); - print " Server Version:".$server_version."\n"; + print " Server Version:".$TLSProxy::Record::tls_version{$server_version}."\n"; print " Session ID Len:".$session_id_len."\n"; print " Ciphersuite:".$ciphersuite."\n"; print " Compression Method:".$comp_meth."\n"; diff --git a/util/perl/TLSProxy/ServerKeyExchange.pm b/util/perl/TLSProxy/ServerKeyExchange.pm index e694c15158c27..c570d1eb3037a 100644 --- a/util/perl/TLSProxy/ServerKeyExchange.pm +++ b/util/perl/TLSProxy/ServerKeyExchange.pm @@ -15,15 +15,23 @@ push @ISA, 'TLSProxy::Message'; sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = $class->SUPER::new( + $isdtls, $server, TLSProxy::Message::MT_SERVER_KEY_EXCHANGE, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, From 7930db0d41f6b3cdec627def8663c18e909bfcb6 Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Mon, 22 Jan 2024 14:12:06 +0100 Subject: [PATCH 80/81] Use open2 instead of open for s_server instance --- util/perl/TLSProxy/Proxy.pm | 65 ++++++------------------------------- 1 file changed, 10 insertions(+), 55 deletions(-) diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm index 0084328a5f17a..08c82c0c52d06 100644 --- a/util/perl/TLSProxy/Proxy.pm +++ b/util/perl/TLSProxy/Proxy.pm @@ -7,6 +7,7 @@ use strict; use POSIX ":sys_wait_h"; +use IPC::Open2; package TLSProxy::Proxy; @@ -203,7 +204,7 @@ sub connect_to_server Proto => $self->{isdtls} ? 'udp' : 'tcp'); if (!defined($sock)) { my $err = $!; - kill(3, $self->{real_serverpid}); + kill(3, $self->{serverpid}); die "unable to connect: $err\n"; } @@ -215,7 +216,6 @@ sub start my ($self) = shift; my $pid; - # Create the Proxy socket my $proxaddr = $self->{proxy_addr}; $proxaddr =~ s/[\[\]]//g; # Remove [ and ] @@ -290,17 +290,13 @@ sub start print STDERR "Server command: $execcmd\n"; } - open(my $savedin, "<&STDIN"); - - # Temporarily replace STDIN so that sink process can inherit it... - $pid = open(STDIN, "$execcmd 2>&1 |") or die "Failed to $execcmd: $!\n"; - $self->{real_serverpid} = $pid; + $pid = IPC::Open2::open2(my $sout, my $sin, $execcmd) or die "Failed to $execcmd: $!\n"; + $self->{serverpid} = $pid; # Process the output from s_server until we find the ACCEPT line, which # tells us what the accepting address and port are. - while (<>) { - print; - s/\R$//; # Better chomp + while (<$sout>) { + chomp; next unless (/^ACCEPT\s.*:(\d+)$/); $self->{server_port} = $1; last; @@ -313,38 +309,6 @@ sub start die "no ACCEPT detected in '$execcmd' output: $?\n"; } - # Just make sure everything else is simply printed [as separate lines]. - # The sub process simply inherits our STD* and will keep consuming - # server's output and printing it as long as there is anything there, - # out of our way. - my $error; - $pid = undef; - if (eval { require Win32::Process; 1; }) { - if (Win32::Process::Create(my $h, $^X, "perl -ne print", 0, 0, ".")) { - $pid = $h->GetProcessID(); - $self->{proc_handle} = $h; # hold handle till next round [or exit] - } else { - $error = Win32::FormatMessage(Win32::GetLastError()); - } - } else { - if (defined($pid = fork)) { - $pid or exec("$^X -ne print") or exit($!); - } else { - $error = $!; - } - } - - # Change back to original stdin - open(STDIN, "<&", $savedin); - close($savedin); - - if (!defined($pid)) { - kill(3, $self->{real_serverpid}); - die "Failed to capture s_server's output: $error\n"; - } - - $self->{serverpid} = $pid; - print STDERR "Server responds on ", "$self->{server_addr}:$self->{server_port}\n"; @@ -401,7 +365,7 @@ sub clientstart # dead-lock... if (!($pid = open(STDOUT, "| $execcmd"))) { my $err = $!; - kill(3, $self->{real_serverpid}); + kill(3, $self->{serverpid}); die "Failed to $execcmd: $err\n"; } $self->{clientpid} = $pid; @@ -417,7 +381,7 @@ sub clientstart # Wait for incoming connection from client my $fdset = IO::Select->new($self->{proxy_sock}); if (!$fdset->can_read(60)) { - kill(3, $self->{real_serverpid}); + kill(3, $self->{serverpid}); die "s_client didn't try to connect\n"; } @@ -476,14 +440,14 @@ sub clientstart $server_sock->shutdown(SHUT_WR); } } else { - kill(3, $self->{real_serverpid}); + kill(3, $self->{serverpid}); die "Unexpected handle"; } } } if ($ctr >= 10) { - kill(3, $self->{real_serverpid}); + kill(3, $self->{serverpid}); print "No progress made\n"; $succes = 0; } @@ -502,15 +466,6 @@ sub clientstart my $pid; if (--$self->{serverconnects} == 0) { $pid = $self->{serverpid}; - print "Waiting for 'perl -ne print' process to close: $pid...\n"; - $pid = waitpid($pid, 0); - if ($pid > 0) { - die "exit code $? from 'perl -ne print' process\n" if $? != 0; - } elsif ($pid == 0) { - kill(3, $self->{real_serverpid}); - die "lost control over $self->{serverpid}?"; - } - $pid = $self->{real_serverpid}; print "Waiting for s_server process to close: $pid...\n"; # it's done already, just collect the exit code [and reap]... waitpid($pid, 0); From 51291dedb15b05ebb26918ed7dcb3f8a31dc0e8f Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Mon, 22 Jan 2024 14:19:06 +0100 Subject: [PATCH 81/81] Use open2 for s_client instance --- util/perl/TLSProxy/Proxy.pm | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm index 08c82c0c52d06..c532f83409b60 100644 --- a/util/perl/TLSProxy/Proxy.pm +++ b/util/perl/TLSProxy/Proxy.pm @@ -326,6 +326,8 @@ sub clientstart if ($self->execute) { my $pid; + my $cin; + my $execcmd = $self->execute ." s_client -engine ossltest" ." -connect $self->{proxy_addr}:$self->{proxy_port}"; @@ -359,11 +361,7 @@ sub clientstart print STDERR "Client command: $execcmd\n"; } - open(my $savedout, ">&STDOUT"); - # If we open pipe with new descriptor, attempt to close it, - # explicitly or implicitly, would incur waitpid and effectively - # dead-lock... - if (!($pid = open(STDOUT, "| $execcmd"))) { + if (!($pid = IPC::Open2::open2(my $cout, $cin, $execcmd))) { my $err = $!; kill(3, $self->{serverpid}); die "Failed to $execcmd: $err\n"; @@ -371,11 +369,7 @@ sub clientstart $self->{clientpid} = $pid; # queue [magic] input - print $self->reneg ? "R" : "test"; - - # this closes client's stdin without waiting for its pid - open(STDOUT, ">&", $savedout); - close($savedout); + print $cin $self->reneg ? "R" : "test"; } # Wait for incoming connection from client