Skip to content

Commit

Permalink
Merge pull request #1695 from esnet/paddingUpdate
Browse files Browse the repository at this point in the history
RSA padding update for authentication feature
  • Loading branch information
swlars authored May 10, 2024
2 parents a56a100 + fbd99b1 commit de9c34b
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/iperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ struct iperf_test
char *server_authorized_users;
EVP_PKEY *server_rsa_private_key;
int server_skew_threshold;
int use_pkcs1_padding;
#endif // HAVE_SSL

/* boolean variables for Options */
Expand Down
9 changes: 9 additions & 0 deletions src/iperf3.1
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ parameter is specified in ms, and defaults to the system settings.
This functionality depends on the TCP_USER_TIMEOUT socket option, and
will not work on systems that do not support it.
.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.
Expand Down
8 changes: 6 additions & 2 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},
{"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},
{"time-skew-threshold", required_argument, NULL, OPT_SERVER_SKEW_THRESHOLD},
{"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},
Expand Down Expand Up @@ -1630,6 +1631,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
return -1;
}
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);
Expand Down Expand Up @@ -2070,7 +2074,7 @@ int test_is_authorized(struct iperf_test *test){
if (test->settings->authtoken){
char *username = NULL, *password = NULL;
time_t ts;
int rc = decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
int rc = decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts, test->use_pkcs1_padding);
if (rc) {
return -1;
}
Expand Down Expand Up @@ -2255,7 +2259,7 @@ send_parameters(struct iperf_test *test)
#if defined(HAVE_SSL)
/* Send authentication parameters */
if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken, test->use_pkcs1_padding);

if (rc) {
cJSON_Delete(j);
Expand Down
1 change: 1 addition & 0 deletions src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ typedef atomic_uint_fast64_t atomic_iperf_size_t;
#define OPT_RCV_TIMEOUT 27
#define OPT_JSON_STREAM 28
#define OPT_SND_TIMEOUT 29
#define OPT_USE_PKCS1_PADDING 30

/* states */
#define TEST_START 1
Expand Down
37 changes: 27 additions & 10 deletions src/iperf_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ int test_load_private_key_from_file(const char *file){
return 0;
}

int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned char **encryptedtext) {
int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned char **encryptedtext, int use_pkcs1_padding) {
#if OPENSSL_VERSION_MAJOR >= 3
EVP_PKEY_CTX *ctx;
#else
Expand All @@ -257,12 +257,19 @@ int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned ch

BIO *bioBuff = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);

int padding = RSA_PKCS1_OAEP_PADDING;
if (use_pkcs1_padding){
padding = RSA_PKCS1_PADDING;
}
#if OPENSSL_VERSION_MAJOR >= 3
EVP_PKEY_encrypt_init(ctx);
EVP_PKEY_CTX_set_rsa_padding(ctx, padding);

EVP_PKEY_encrypt(ctx, *encryptedtext, &encryptedtext_len, rsa_buffer, rsa_buffer_len);
EVP_PKEY_CTX_free(ctx);
#else
encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, RSA_PKCS1_PADDING);
encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, padding);
RSA_free(rsa);
#endif

Expand All @@ -280,7 +287,7 @@ int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned ch
return 0;
}

int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, EVP_PKEY *private_key, unsigned char **plaintext) {
int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, EVP_PKEY *private_key, unsigned char **plaintext, int use_pkcs1_padding) {
#if OPENSSL_VERSION_MAJOR >= 3
EVP_PKEY_CTX *ctx;
#else
Expand All @@ -307,21 +314,31 @@ 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);

int padding = RSA_PKCS1_OAEP_PADDING;
if (use_pkcs1_padding){
padding = RSA_PKCS1_PADDING;
}
#if OPENSSL_VERSION_MAJOR >= 3
plaintext_len = keysize;
EVP_PKEY_decrypt_init(ctx);
int ret = EVP_PKEY_CTX_set_rsa_padding(ctx, padding);
if (ret < 0){
goto errreturn;
}
EVP_PKEY_decrypt(ctx, *plaintext, &plaintext_len, rsa_buffer, rsa_buffer_len);
EVP_PKEY_CTX_free(ctx);
#else
plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, RSA_PKCS1_PADDING);
plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, padding);
RSA_free(rsa);
#endif

OPENSSL_free(rsa_buffer);
BIO_free(bioBuff);

if (plaintext_len <= 0) {
goto errreturn;
/* Treat a decryption error as an empty string. */
if (plaintext_len < 0) {
plaintext_len = 0;
}

return plaintext_len;
Expand All @@ -331,7 +348,7 @@ int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedt
return 0;
}

int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken){
int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken, int use_pkcs1_padding){
time_t t = time(NULL);
time_t utc_seconds = mktime(localtime(&t));

Expand All @@ -348,7 +365,7 @@ int encode_auth_setting(const char *username, const char *password, EVP_PKEY *pu

unsigned char *encrypted = NULL;
int encrypted_len;
encrypted_len = encrypt_rsa_message(text, public_key, &encrypted);
encrypted_len = encrypt_rsa_message(text, public_key, &encrypted, use_pkcs1_padding);
free(text);
if (encrypted_len < 0) {
return -1;
Expand All @@ -359,15 +376,15 @@ int encode_auth_setting(const char *username, const char *password, EVP_PKEY *pu
return (0); //success
}

int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts, int use_pkcs1_padding){
unsigned char *encrypted_b64 = NULL;
size_t encrypted_len_b64;
int64_t utc_seconds;
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_key, &plaintext);
plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_key, &plaintext, use_pkcs1_padding);
free(encrypted_b64);
if (plaintext_len < 0) {
return -1;
Expand Down
4 changes: 2 additions & 2 deletions src/iperf_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ EVP_PKEY *load_pubkey_from_file(const char *file);
EVP_PKEY *load_pubkey_from_base64(const char *buffer);
EVP_PKEY *load_privkey_from_file(const char *file);
EVP_PKEY *load_privkey_from_base64(const char *buffer);
int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken);
int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts);
int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken, int use_pkcs1_padding);
int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, 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, int skew_threshold);
ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream);
1 change: 1 addition & 0 deletions src/iperf_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" credentials\n"
" --time-skew-threshold time skew threshold (in seconds) between the server\n"
" and client during the authentication process\n"
" --use-pkcs1-padding use pkcs1 padding at your own risk\n"
#endif //HAVE_SSL
"Client specific:\n"
" -c, --client <host>[%%<dev>] run in client mode, connecting to <host>\n"
Expand Down
5 changes: 3 additions & 2 deletions src/t_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ test_authtoken(const char *authUser, const char *authPassword, EVP_PKEY *pubkey,
char *decodePassword;
time_t decodeTime;

assert(encode_auth_setting(authUser, authPassword, pubkey, &authToken) == 0);
assert(decode_auth_setting(0, authToken, privkey, &decodeUser, &decodePassword, &decodeTime) == 0);
int use_pkcs1_padding = 1;
assert(encode_auth_setting(authUser, authPassword, pubkey, &authToken, use_pkcs1_padding) == 0);
assert(decode_auth_setting(0, authToken, privkey, &decodeUser, &decodePassword, &decodeTime, use_pkcs1_padding) == 0);

assert(strcmp(decodeUser, authUser) == 0);
assert(strcmp(decodePassword, authPassword) == 0);
Expand Down

0 comments on commit de9c34b

Please sign in to comment.