Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSA padding update for authentication feature #1695

Merged
merged 3 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading