iperf3/0006-cve-2024-26306.patch

232 lines
10 KiB
Diff

From 299b356df6939f71619bf45bf7a7d2222e17d840 Mon Sep 17 00:00:00 2001
From: Sarah Larsen <swlarsen@Sarahs-MBP.lan>
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 <host> run in client mode, connecting to <host>\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];