diff options
Diffstat (limited to 'lib/auth/rsa_psk.c')
-rw-r--r-- | lib/auth/rsa_psk.c | 640 |
1 files changed, 314 insertions, 326 deletions
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c index e72d55d32a..23ff898bcd 100644 --- a/lib/auth/rsa_psk.c +++ b/lib/auth/rsa_psk.c @@ -49,68 +49,68 @@ #include <gnutls_datum.h> #include <gnutls_state.h> -static int _gnutls_gen_rsa_psk_client_kx (gnutls_session_t session, - gnutls_buffer_st * data); -static int _gnutls_proc_rsa_psk_client_kx (gnutls_session_t, uint8_t *, - size_t); +static int _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session, + gnutls_buffer_st * data); +static int _gnutls_proc_rsa_psk_client_kx(gnutls_session_t, uint8_t *, + size_t); const mod_auth_st rsa_psk_auth_struct = { - "RSA PSK", - _gnutls_gen_cert_server_crt, - NULL, /* generate_client_certificate */ - _gnutls_gen_psk_server_kx, - _gnutls_gen_rsa_psk_client_kx, - NULL, /* generate_client_cert_vrfy */ - NULL, /* generate_server_certificate_request */ - _gnutls_proc_crt, - NULL, /* process_client_certificate */ - _gnutls_proc_psk_server_kx, - _gnutls_proc_rsa_psk_client_kx, - NULL, /* process_client_cert_vrfy */ - NULL /* process_server_certificate_reuqest */ + "RSA PSK", + _gnutls_gen_cert_server_crt, + NULL, /* generate_client_certificate */ + _gnutls_gen_psk_server_kx, + _gnutls_gen_rsa_psk_client_kx, + NULL, /* generate_client_cert_vrfy */ + NULL, /* generate_server_certificate_request */ + _gnutls_proc_crt, + NULL, /* process_client_certificate */ + _gnutls_proc_psk_server_kx, + _gnutls_proc_rsa_psk_client_kx, + NULL, /* process_client_cert_vrfy */ + NULL /* process_server_certificate_reuqest */ }; /* Set the PSK premaster secret. */ static int -set_rsa_psk_session_key (gnutls_session_t session, - gnutls_datum_t *ppsk, gnutls_datum_t * rsa_secret) +set_rsa_psk_session_key(gnutls_session_t session, + gnutls_datum_t * ppsk, gnutls_datum_t * rsa_secret) { - unsigned char *p; - size_t rsa_secret_size; - int ret; - - - rsa_secret_size = rsa_secret->size; - - /* set the session key - */ - session->key.key.size = 2 + rsa_secret_size + 2 + ppsk->size; - session->key.key.data = gnutls_malloc (session->key.key.size); - if (session->key.key.data == NULL) - { - gnutls_assert (); - ret = GNUTLS_E_MEMORY_ERROR; - goto error; - } - - /* format of the premaster secret: - * (uint16_t) other_secret size (48) - * other_secret: 2 byte version + 46 byte random - * (uint16_t) psk_size - * the psk - */ - _gnutls_write_uint16 (rsa_secret_size, session->key.key.data); - memcpy (&session->key.key.data[2], rsa_secret->data, rsa_secret->size); - p = &session->key.key.data[rsa_secret_size + 2]; - _gnutls_write_uint16 (ppsk->size, p); - if (ppsk->data != NULL) - memcpy (p + 2, ppsk->data, ppsk->size); - - ret = 0; - -error: - return ret; + unsigned char *p; + size_t rsa_secret_size; + int ret; + + + rsa_secret_size = rsa_secret->size; + + /* set the session key + */ + session->key.key.size = 2 + rsa_secret_size + 2 + ppsk->size; + session->key.key.data = gnutls_malloc(session->key.key.size); + if (session->key.key.data == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; + goto error; + } + + /* format of the premaster secret: + * (uint16_t) other_secret size (48) + * other_secret: 2 byte version + 46 byte random + * (uint16_t) psk_size + * the psk + */ + _gnutls_write_uint16(rsa_secret_size, session->key.key.data); + memcpy(&session->key.key.data[2], rsa_secret->data, + rsa_secret->size); + p = &session->key.key.data[rsa_secret_size + 2]; + _gnutls_write_uint16(ppsk->size, p); + if (ppsk->data != NULL) + memcpy(p + 2, ppsk->data, ppsk->size); + + ret = 0; + + error: + return ret; } /* Generate client key exchange message @@ -124,297 +124,285 @@ error: * } ClientKeyExchange; */ static int -_gnutls_gen_rsa_psk_client_kx (gnutls_session_t session, - gnutls_buffer_st * data) +_gnutls_gen_rsa_psk_client_kx(gnutls_session_t session, + gnutls_buffer_st * data) { - cert_auth_info_t auth = session->key.auth_info; - gnutls_datum_t sdata; /* data to send */ - gnutls_pk_params_st params; - gnutls_psk_client_credentials_t cred; - gnutls_datum_t username, key; - int ret, free; - - if (auth == NULL) - { - /* this shouldn't have happened. The proc_certificate - * function should have detected that. - */ - gnutls_assert (); - return GNUTLS_E_INSUFFICIENT_CREDENTIALS; - } - - gnutls_datum_t premaster_secret; - premaster_secret.size = GNUTLS_MASTER_SIZE; - premaster_secret.data = gnutls_secure_malloc (premaster_secret.size); - - if (premaster_secret.data == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } - - /* Generate random */ - ret = _gnutls_rnd (GNUTLS_RND_RANDOM, premaster_secret.data, - premaster_secret.size); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - /* Set version */ - if (session->internals.rsa_pms_version[0] == 0) - { - premaster_secret.data[0] = _gnutls_get_adv_version_major (session); - premaster_secret.data[1] = _gnutls_get_adv_version_minor (session); - } - else - { /* use the version provided */ - premaster_secret.data[0] = session->internals.rsa_pms_version[0]; - premaster_secret.data[1] = session->internals.rsa_pms_version[1]; - } - - /* move RSA parameters to key (session). - */ - if ((ret = _gnutls_get_public_rsa_params (session, ¶ms)) < 0) - { - gnutls_assert (); - return ret; - } - - /* Encrypt premaster secret */ - if ((ret = - _gnutls_pk_encrypt (GNUTLS_PK_RSA, &sdata, &premaster_secret, - ¶ms)) < 0) - { - gnutls_assert (); - return ret; - } - - gnutls_pk_params_release (¶ms); - - cred = (gnutls_psk_client_credentials_t) - _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL); - - if (cred == NULL) - { - gnutls_assert (); - return GNUTLS_E_INSUFFICIENT_CREDENTIALS; - } - - ret = _gnutls_find_psk_key( session, cred, &username, &key, &free); - if (ret < 0) - return gnutls_assert_val(ret); - - /* Here we set the PSK key */ - ret = set_rsa_psk_session_key (session, &key, &premaster_secret); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - /* Create message for client key exchange - * - * struct { - * uint8_t psk_identity<0..2^16-1>; - * EncryptedPreMasterSecret; - * } - */ - - /* Write psk_identity and EncryptedPreMasterSecret into data stream - */ - ret = _gnutls_buffer_append_data_prefix (data, 16, cred->username.data, - cred->username.size); - if (ret < 0) - { - gnutls_assert(); - goto cleanup; - } - - ret = _gnutls_buffer_append_data_prefix (data, 16, sdata.data, sdata.size); - if (ret < 0) - { - gnutls_assert(); - goto cleanup; - } - - ret = 0; - -cleanup: - _gnutls_free_datum (&sdata); - _gnutls_free_datum (&premaster_secret); - if (free) - { - gnutls_free(key.data); - gnutls_free(username.data); - } - - return data->length; + cert_auth_info_t auth = session->key.auth_info; + gnutls_datum_t sdata; /* data to send */ + gnutls_pk_params_st params; + gnutls_psk_client_credentials_t cred; + gnutls_datum_t username, key; + int ret, free; + + if (auth == NULL) { + /* this shouldn't have happened. The proc_certificate + * function should have detected that. + */ + gnutls_assert(); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + gnutls_datum_t premaster_secret; + premaster_secret.size = GNUTLS_MASTER_SIZE; + premaster_secret.data = + gnutls_secure_malloc(premaster_secret.size); + + if (premaster_secret.data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + /* Generate random */ + ret = _gnutls_rnd(GNUTLS_RND_RANDOM, premaster_secret.data, + premaster_secret.size); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* Set version */ + if (session->internals.rsa_pms_version[0] == 0) { + premaster_secret.data[0] = + _gnutls_get_adv_version_major(session); + premaster_secret.data[1] = + _gnutls_get_adv_version_minor(session); + } else { /* use the version provided */ + premaster_secret.data[0] = + session->internals.rsa_pms_version[0]; + premaster_secret.data[1] = + session->internals.rsa_pms_version[1]; + } + + /* move RSA parameters to key (session). + */ + if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) { + gnutls_assert(); + return ret; + } + + /* Encrypt premaster secret */ + if ((ret = + _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &premaster_secret, + ¶ms)) < 0) { + gnutls_assert(); + return ret; + } + + gnutls_pk_params_release(¶ms); + + cred = (gnutls_psk_client_credentials_t) + _gnutls_get_cred(session, GNUTLS_CRD_PSK, NULL); + + if (cred == NULL) { + gnutls_assert(); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + ret = _gnutls_find_psk_key(session, cred, &username, &key, &free); + if (ret < 0) + return gnutls_assert_val(ret); + + /* Here we set the PSK key */ + ret = set_rsa_psk_session_key(session, &key, &premaster_secret); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + /* Create message for client key exchange + * + * struct { + * uint8_t psk_identity<0..2^16-1>; + * EncryptedPreMasterSecret; + * } + */ + + /* Write psk_identity and EncryptedPreMasterSecret into data stream + */ + ret = + _gnutls_buffer_append_data_prefix(data, 16, + cred->username.data, + cred->username.size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = + _gnutls_buffer_append_data_prefix(data, 16, sdata.data, + sdata.size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = 0; + + cleanup: + _gnutls_free_datum(&sdata); + _gnutls_free_datum(&premaster_secret); + if (free) { + gnutls_free(key.data); + gnutls_free(username.data); + } + + return data->length; } /* Process the client key exchange message */ static int -_gnutls_proc_rsa_psk_client_kx (gnutls_session_t session, uint8_t * data, - size_t _data_size) +_gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data, + size_t _data_size) { - gnutls_datum_t username; - psk_auth_info_t info; - gnutls_datum_t plaintext; - gnutls_datum_t ciphertext; - gnutls_datum_t pwd_psk = {NULL, 0}; - int ret, dsize; - int randomize_key = 0; - ssize_t data_size = _data_size; - gnutls_psk_server_credentials_t cred; - gnutls_datum_t premaster_secret = {NULL, 0}; - - cred = (gnutls_psk_server_credentials_t) - _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL); - - if (cred == NULL) - { - gnutls_assert (); - return GNUTLS_E_INSUFFICIENT_CREDENTIALS; - } - - ret = _gnutls_auth_info_set (session, GNUTLS_CRD_PSK, - sizeof (psk_auth_info_st), 1); - if (ret < 0) - { - gnutls_assert (); - return ret; - } + gnutls_datum_t username; + psk_auth_info_t info; + gnutls_datum_t plaintext; + gnutls_datum_t ciphertext; + gnutls_datum_t pwd_psk = { NULL, 0 }; + int ret, dsize; + int randomize_key = 0; + ssize_t data_size = _data_size; + gnutls_psk_server_credentials_t cred; + gnutls_datum_t premaster_secret = { NULL, 0 }; + + cred = (gnutls_psk_server_credentials_t) + _gnutls_get_cred(session, GNUTLS_CRD_PSK, NULL); + + if (cred == NULL) { + gnutls_assert(); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + ret = _gnutls_auth_info_set(session, GNUTLS_CRD_PSK, + sizeof(psk_auth_info_st), 1); + if (ret < 0) { + gnutls_assert(); + return ret; + } /*** 1. Extract user psk_identity ***/ - DECR_LEN (data_size, 2); - username.size = _gnutls_read_uint16 (&data[0]); + DECR_LEN(data_size, 2); + username.size = _gnutls_read_uint16(&data[0]); - DECR_LEN (data_size, username.size); + DECR_LEN(data_size, username.size); - username.data = &data[2]; + username.data = &data[2]; - /* copy the username to the auth info structures - */ - info = _gnutls_get_auth_info (session); + /* copy the username to the auth info structures + */ + info = _gnutls_get_auth_info(session); - if (username.size > MAX_USERNAME_SIZE) - { - gnutls_assert (); - return GNUTLS_E_ILLEGAL_SRP_USERNAME; - } + if (username.size > MAX_USERNAME_SIZE) { + gnutls_assert(); + return GNUTLS_E_ILLEGAL_SRP_USERNAME; + } - memcpy (info->username, username.data, username.size); - info->username[username.size] = 0; + memcpy(info->username, username.data, username.size); + info->username[username.size] = 0; - /* Adjust data so it points to EncryptedPreMasterSecret */ - data += username.size + 2; + /* Adjust data so it points to EncryptedPreMasterSecret */ + data += username.size + 2; /*** 2. Decrypt and extract EncryptedPreMasterSecret ***/ - DECR_LEN (data_size, 2); - ciphertext.data = &data[2]; - dsize = _gnutls_read_uint16 (data); - - if (dsize != data_size) - { - gnutls_assert (); - return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; - } - ciphertext.size = dsize; - - ret = gnutls_privkey_decrypt_data (session->internals.selected_key, 0, - &ciphertext, &plaintext); - if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) - { - /* In case decryption fails then don't inform - * the peer. Just use a random key. (in order to avoid - * attack against pkcs-1 formating). - */ - gnutls_assert (); - _gnutls_debug_log ("auth_rsa_psk: Possible PKCS #1 format attack\n"); - randomize_key = 1; - } - else - { - /* If the secret was properly formatted, then - * check the version number. - */ - if (_gnutls_get_adv_version_major (session) != plaintext.data[0] || - (session->internals.priorities.allow_wrong_pms == 0 && - _gnutls_get_adv_version_minor (session) != plaintext.data[1])) - { - /* No error is returned here, if the version number check - * fails. We proceed normally. - * That is to defend against the attack described in the paper - * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, - * Ondej Pokorny and Tomas Rosa. - */ - gnutls_assert (); - _gnutls_debug_log - ("auth_rsa: Possible PKCS #1 version check format attack\n"); - } - } - - - if (randomize_key != 0) - { - premaster_secret.size = GNUTLS_MASTER_SIZE; - premaster_secret.data = gnutls_malloc (premaster_secret.size); - if (premaster_secret.data == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } - - /* we do not need strong random numbers here. - */ - ret = _gnutls_rnd (GNUTLS_RND_NONCE, premaster_secret.data, - premaster_secret.size); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - } - else - { - premaster_secret.data = plaintext.data; - premaster_secret.size = plaintext.size; - } - - /* This is here to avoid the version check attack - * discussed above. - */ - - premaster_secret.data[0] = _gnutls_get_adv_version_major (session); - premaster_secret.data[1] = _gnutls_get_adv_version_minor (session); - - /* find the key of this username - */ - ret = _gnutls_psk_pwd_find_entry (session, info->username, &pwd_psk); - if (ret < 0) - { - gnutls_assert(); - goto cleanup; - } - - ret = set_rsa_psk_session_key (session, &pwd_psk, &premaster_secret); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - ret = 0; -cleanup: - _gnutls_free_datum (&pwd_psk); - _gnutls_free_datum (&premaster_secret); - - return ret; + DECR_LEN(data_size, 2); + ciphertext.data = &data[2]; + dsize = _gnutls_read_uint16(data); + + if (dsize != data_size) { + gnutls_assert(); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + ciphertext.size = dsize; + + ret = + gnutls_privkey_decrypt_data(session->internals.selected_key, 0, + &ciphertext, &plaintext); + if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) { + /* In case decryption fails then don't inform + * the peer. Just use a random key. (in order to avoid + * attack against pkcs-1 formating). + */ + gnutls_assert(); + _gnutls_debug_log + ("auth_rsa_psk: Possible PKCS #1 format attack\n"); + randomize_key = 1; + } else { + /* If the secret was properly formatted, then + * check the version number. + */ + if (_gnutls_get_adv_version_major(session) != + plaintext.data[0] + || (session->internals.priorities.allow_wrong_pms == 0 + && _gnutls_get_adv_version_minor(session) != + plaintext.data[1])) { + /* No error is returned here, if the version number check + * fails. We proceed normally. + * That is to defend against the attack described in the paper + * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, + * Ondej Pokorny and Tomas Rosa. + */ + gnutls_assert(); + _gnutls_debug_log + ("auth_rsa: Possible PKCS #1 version check format attack\n"); + } + } + + + if (randomize_key != 0) { + premaster_secret.size = GNUTLS_MASTER_SIZE; + premaster_secret.data = + gnutls_malloc(premaster_secret.size); + if (premaster_secret.data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + /* we do not need strong random numbers here. + */ + ret = _gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data, + premaster_secret.size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + } else { + premaster_secret.data = plaintext.data; + premaster_secret.size = plaintext.size; + } + + /* This is here to avoid the version check attack + * discussed above. + */ + + premaster_secret.data[0] = _gnutls_get_adv_version_major(session); + premaster_secret.data[1] = _gnutls_get_adv_version_minor(session); + + /* find the key of this username + */ + ret = + _gnutls_psk_pwd_find_entry(session, info->username, &pwd_psk); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = + set_rsa_psk_session_key(session, &pwd_psk, &premaster_secret); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = 0; + cleanup: + _gnutls_free_datum(&pwd_psk); + _gnutls_free_datum(&premaster_secret); + + return ret; } -#endif /* ENABLE_PSK */ +#endif /* ENABLE_PSK */ |