diff --git a/0006-cve-2024-26306.patch b/0006-cve-2024-26306.patch new file mode 100644 index 0000000..b8ed1f5 --- /dev/null +++ b/0006-cve-2024-26306.patch @@ -0,0 +1,231 @@ +From 299b356df6939f71619bf45bf7a7d2222e17d840 Mon Sep 17 00:00:00 2001 +From: Sarah Larsen +Date: Wed, 20 Mar 2024 17:02:31 -0700 +Subject: [PATCH] Using OAEP padding instead of PKCS1 padding for OpenSSL. Fix + for CVE-2024-26306. + +Special thanks to Hubert Kario at Red Hat for finding the vulnerability. + +diff --git a/src/iperf.h b/src/iperf.h +index f137b07..f6c0313 100755 +--- a/src/iperf.h ++++ b/src/iperf.h +@@ -260,6 +260,7 @@ struct iperf_test + int ctrl_sck_mss; /* MSS for the control channel */ + char *server_rsa_private_key; + char *server_authorized_users; ++ int use_pkcs1_padding; + + /* boolean variables for Options */ + int daemon; /* -D option */ +diff --git a/src/iperf_api.c b/src/iperf_api.c +index d40561c10..7fb741e77 100644 +--- a/src/iperf_api.c ++++ b/src/iperf_api.c +@@ -1137,6 +1137,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + {"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY}, + {"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY}, + {"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS}, ++ {"use-pkcs1-padding", no_argument, NULL, OPT_USE_PKCS1_PADDING}, + #endif /* HAVE_SSL */ + {"fq-rate", required_argument, NULL, OPT_FQ_RATE}, + {"pacing-timer", required_argument, NULL, OPT_PACING_TIMER}, +@@ -1630,6 +1631,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + case OPT_SERVER_AUTHORIZED_USERS: + test->server_authorized_users = strdup(optarg); + break; ++ case OPT_USE_PKCS1_PADDING: ++ test->use_pkcs1_padding = 1; ++ break; + #endif /* HAVE_SSL */ + case OPT_PACING_TIMER: + test->settings->pacing_timer = unit_atoi(optarg); +@@ -1100,7 +1104,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + i_errno = IESETCLIENTAUTH; + return -1; + } +- encode_auth_setting(client_username, client_password, client_rsa_public_key, &test->settings->authtoken); ++ encode_auth_setting(client_username, client_password, client_rsa_public_key, &test->settings->authtoken, test->use_pkcs1_padding); + } + + if (test->role == 'c' && (test->server_rsa_private_key || test->server_authorized_users)){ +@@ -1346,7 +1350,7 @@ int test_is_authorized(struct iperf_test *test){ + if (test->settings->authtoken){ + char *username = NULL, *password = NULL; + time_t ts; +- decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts); ++ decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts, test->use_pkcs1_padding); + int ret = check_authentication(username, password, ts, test->server_authorized_users); + if (ret == 0){ + iperf_printf(test, report_authetication_successed, username, ts); +diff --git a/src/iperf_locale.c b/src/iperf_locale.c +index d5a5354..3b6860d 100644 +--- a/src/iperf_locale.c ++++ b/src/iperf_locale.c +@@ -128,6 +128,7 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" + " authentication credentials\n" + " --authorized-users-path path to the configuration file containing user\n" + " credentials\n" ++ " --use-pkcs1-padding use pkcs1 padding at your own risk\n" + #endif //HAVE_SSL + "Client specific:\n" + " -c, --client run in client mode, connecting to \n" +diff --git a/src/iperf_api.h b/src/iperf_api.h +index 3a5df03..255227c 100755 +--- a/src/iperf_api.h ++++ b/src/iperf_api.h +@@ -68,6 +68,7 @@ struct iperf_stream; + #define OPT_SERVER_AUTHORIZED_USERS 15 + #define OPT_PACING_TIMER 16 + #define OPT_CONNECT_TIMEOUT 17 ++#define OPT_USE_PKCS1_PADDING 30 + + /* states */ + #define TEST_START 1 +diff --git a/src/iperf_auth.h b/src/iperf_auth.h +index 38971d8..1f78699 100644 +--- a/src/iperf_auth.h ++++ b/src/iperf_auth.h +@@ -30,7 +30,7 @@ + + int test_load_pubkey(const char *public_keyfile); + int test_load_private_key(const char *private_keyfile); +-int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken); +-int decode_auth_setting(int enable_debug, const char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts); ++int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken, int use_pkcs1_padding); ++int decode_auth_setting(int enable_debug, const char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts, int use_pkcs1_padding); + int check_authentication(const char *username, const char *password, const time_t ts, const char *filename); + ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream); +diff --git a/src/iperf3.1 b/src/iperf3.1 +index 1be8cc3..87c3e02 100644 +--- a/src/iperf3.1 ++++ b/src/iperf3.1 +@@ -155,6 +155,15 @@ send output to a log file. + force flushing output at every interval. + Used to avoid buffering when sending output to pipe. + .TP ++.BR --use-pkcs1-padding ++This option is only meaningful when using iperf3's authentication ++features. Versions of iperf3 prior to 3.17 used PCKS1 padding in the ++RSA-encrypted credentials, which was vulnerable to a side-channel ++attack that could reveal a server's private key. Beginning with ++iperf-3.17, OAEP padding is used, however this is a breaking change ++that is not compatible with older iperf3 versions. Use this option to ++preserve the less secure, but more compatible, behavior. ++.TP + .BR -d ", " --debug " " + emit debugging output. + Primarily (perhaps exclusively) of use to developers. +diff --git a/src/iperf_auth.c b/src/iperf_auth.c +index f8d2b0a..2d7d519 100644 +--- a/src/iperf_auth.c ++++ b/src/iperf_auth.c +@@ -194,11 +194,12 @@ int test_load_private_key(const char *file){ + return 0; + } + +-int encrypt_rsa_message(const char *plaintext, const char *public_keyfile, unsigned char **encryptedtext) { ++int encrypt_rsa_message(const char *plaintext, const char *public_keyfile, unsigned char **encryptedtext, int use_pkcs1_padding) { + EVP_PKEY *public_key = NULL; + RSA *rsa = NULL; +- unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING; +- int keysize, encryptedtext_len, rsa_buffer_len; ++ unsigned char *rsa_buffer = NULL; ++ size_t encryptedtext_len = 0; ++ int rsa_buffer_len, keysize; + + public_key = load_pubkey(public_keyfile); + rsa = EVP_PKEY_get1_RSA(public_key); +@@ -210,20 +211,35 @@ int encrypt_rsa_message(const char *plaintext, const char *public_keyfile, unsig + + BIO *bioBuff = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext)); + rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2); +- encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad); ++ ++ int padding = RSA_PKCS1_OAEP_PADDING; ++ if (use_pkcs1_padding){ ++ padding = RSA_PKCS1_PADDING; ++ } ++ ++ encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, padding); + + RSA_free(rsa); + OPENSSL_free(rsa_buffer); +- OPENSSL_free(bioBuff); ++ OPENSSL_free(bioBuff); ++ ++ if (encryptedtext_len < 0) { ++ goto errreturn; ++ } ++ ++ return encryptedtext_len; + +- return encryptedtext_len; ++ errreturn: ++ fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ++ return 0; + } + +-int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, const char *private_keyfile, unsigned char **plaintext) { ++int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, const char *private_keyfile, unsigned char **plaintext, int use_pkcs1_padding) { + EVP_PKEY *private_key = NULL; + RSA *rsa = NULL; +- unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING; +- int plaintext_len, rsa_buffer_len, keysize; ++ unsigned char *rsa_buffer = NULL; ++ size_t plaintext_len = 0; ++ int rsa_buffer_len, keysize; + + private_key = load_key(private_keyfile); + rsa = EVP_PKEY_get1_RSA(private_key); +@@ -235,35 +250,45 @@ int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedt + + BIO *bioBuff = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len); + rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2); +- plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad); ++ ++ int padding = RSA_PKCS1_OAEP_PADDING; ++ if (use_pkcs1_padding){ ++ padding = RSA_PKCS1_PADDING; ++ } ++ ++ plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, padding); + + RSA_free(rsa); + OPENSSL_free(rsa_buffer); + OPENSSL_free(bioBuff); + ++ if (plaintext_len < 0) { ++ plaintext_len = 0; ++ } ++ + return plaintext_len; + } + +-int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken){ ++int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken, int use_pkcs1_padding){ + time_t t = time(NULL); + time_t utc_seconds = mktime(localtime(&t)); + char text[150]; + sprintf (text, "user: %s\npwd: %s\nts: %ld", username, password, utc_seconds); + unsigned char *encrypted = NULL; + int encrypted_len; +- encrypted_len = encrypt_rsa_message(text, public_keyfile, &encrypted); ++ encrypted_len = encrypt_rsa_message(text, public_keyfile, &encrypted, use_pkcs1_padding); + Base64Encode(encrypted, encrypted_len, authtoken); + return (0); //success + } + +-int decode_auth_setting(int enable_debug, char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts){ ++int decode_auth_setting(int enable_debug, char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts, int use_pkcs1_padding){ + unsigned char *encrypted_b64 = NULL; + size_t encrypted_len_b64; + Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64); + + unsigned char *plaintext = NULL; + int plaintext_len; +- plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_keyfile, &plaintext); ++ plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_keyfile, &plaintext, use_pkcs1_padding); + plaintext[plaintext_len] = '\0'; + + char s_username[20], s_password[20]; diff --git a/iperf3.spec b/iperf3.spec index fbaa0b6..f55616d 100644 --- a/iperf3.spec +++ b/iperf3.spec @@ -1,6 +1,6 @@ Name: iperf3 Version: 3.5 -Release: 9%{?dist} +Release: 10%{?dist} Summary: Measurement tool for TCP/UDP bandwidth performance Group: Applications/Internet @@ -15,6 +15,7 @@ Patch0002: 0002-udp-counters-manpage.patch Patch0003: 0003-covscan-sctp.patch Patch0004: 0004-cve-2023-38403.patch Patch0005: 0005-cve-2023-7250.patch +Patch0006: 0006-cve-2024-26306.patch %description Iperf is a tool to measure maximum TCP bandwidth, allowing the tuning of @@ -62,6 +63,9 @@ rm -f %{buildroot}%{_libdir}/libiperf.la %{_libdir}/*.so %changelog +* Tue Jun 11 2024 Michal Ruprich - 3.5-10 +- Resolves: RHEL-29578 - vulnerable to marvin attack if the authentication option is used + * Tue Jun 04 2024 Michal Ruprich - 3.5-9 - Resolves: RHEL-17069 - possible denial of service