/* just read the username from the client key exchange. */ int _gnutls_proc_psk_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { ssize_t data_size = _data_size; int ret; gnutls_datum_t username; gnutls_psk_server_credentials_t cred; psk_auth_info_t info; cred = (gnutls_psk_server_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_PSK, sizeof (psk_auth_info_st), 1)) < 0) { gnutls_assert (); return ret; } DECR_LEN (data_size, 2); username.size = _gnutls_read_uint16 (&data[0]); DECR_LEN (data_size, username.size); username.data = &data[2]; /* 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; } memcpy (info->username, username.data, username.size); info->username[username.size] = 0; ret = _gnutls_set_psk_session_key (session, NULL); if (ret < 0) { gnutls_assert (); goto error; } ret = 0; error: return ret; }
static int proc_ecdhe_psk_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { int ret, psk_size; ssize_t data_size = _data_size; /* set auth_info */ if ((ret = _gnutls_auth_info_set(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1)) < 0) { gnutls_assert(); return ret; } DECR_LEN(data_size, 2); psk_size = _gnutls_read_uint16(data); DECR_LEN(data_size, psk_size); data += 2 + psk_size; ret = _gnutls_proc_ecdh_common_server_kx(session, data, data_size); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
int _gnutls_proc_ecdh_common_client_kx(gnutls_session_t session, uint8_t * data, size_t _data_size, gnutls_ecc_curve_t curve, gnutls_datum_t * psk_key) { ssize_t data_size = _data_size; int ret, i = 0; int point_size; if (curve == GNUTLS_ECC_CURVE_INVALID) return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); DECR_LEN(data_size, 1); point_size = data[i]; i += 1; DECR_LEN(data_size, point_size); ret = _gnutls_ecc_ansi_x963_import(&data[i], point_size, &session->key.ecdh_x, &session->key.ecdh_y); if (ret < 0) return gnutls_assert_val(ret); /* generate pre-shared key */ ret = calc_ecdh_key(session, psk_key, curve); if (ret < 0) return gnutls_assert_val(ret); return 0; }
static int _gnutls_max_record_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { ssize_t new_size; ssize_t data_size = _data_size; extension_priv_data_t epriv; int ret; if (session->security_parameters.entity == GNUTLS_SERVER) { if (data_size > 0) { DECR_LEN(data_size, 1); new_size = _gnutls_mre_num2record(data[0]); if (new_size < 0) { gnutls_assert(); return new_size; } session->security_parameters.max_record_send_size = new_size; session->security_parameters.max_record_recv_size = new_size; } } else { /* CLIENT SIDE - we must check if the sent record size is the right one */ if (data_size > 0) { ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_MAX_RECORD_SIZE, &epriv); if (ret < 0) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } if (data_size != 1) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } new_size = _gnutls_mre_num2record(data[0]); if (new_size < 0 || new_size != (intptr_t) epriv) { gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } else { session->security_parameters. max_record_recv_size = (intptr_t)epriv; } } } return 0; }
static int unpack_ticket(const gnutls_datum_t *ticket_data, struct ticket_st *ticket) { const uint8_t * data = ticket_data->data; ssize_t data_size = ticket_data->size; const uint8_t *encrypted_state; /* Format: * Key name * IV * data length * encrypted data * MAC */ DECR_LEN(data_size, TICKET_KEY_NAME_SIZE); memcpy(ticket->key_name, data, TICKET_KEY_NAME_SIZE); data += TICKET_KEY_NAME_SIZE; DECR_LEN(data_size, TICKET_IV_SIZE); memcpy(ticket->IV, data, TICKET_IV_SIZE); data += TICKET_IV_SIZE; DECR_LEN(data_size, 2); ticket->encrypted_state_len = _gnutls_read_uint16(data); data += 2; encrypted_state = data; DECR_LEN(data_size, ticket->encrypted_state_len); data += ticket->encrypted_state_len; DECR_LEN(data_size, TICKET_MAC_SIZE); memcpy(ticket->mac, data, TICKET_MAC_SIZE); ticket->encrypted_state = gnutls_malloc(ticket->encrypted_state_len); if (!ticket->encrypted_state) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } memcpy(ticket->encrypted_state, encrypted_state, ticket->encrypted_state_len); return 0; }
static int _gnutls_signature_algorithm_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { ssize_t data_size = _data_size; int ret; if (session->security_parameters.entity == GNUTLS_CLIENT) { /* nothing for now */ gnutls_assert(); /* Although TLS 1.2 mandates that we must not accept reply * to this message, there are good reasons to just ignore it. Check * http://www.ietf.org/mail-archive/web/tls/current/msg03880.html */ /* return GNUTLS_E_UNEXPECTED_PACKET; */ } else { /* SERVER SIDE - we must check if the sent cert type is the right one */ if (data_size >= 2) { uint16_t len; DECR_LEN(data_size, 2); len = _gnutls_read_uint16(data); DECR_LEN(data_size, len); if (data_size > 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); ret = _gnutls_sign_algorithm_parse_data(session, data + 2, len); if (ret < 0) { gnutls_assert(); return ret; } } else { return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } } return 0; }
int _gnutls_proc_ecdh_common_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { int i, ret, point_size; gnutls_ecc_curve_t curve; ssize_t data_size = _data_size; /* just in case we are resuming a session */ gnutls_pk_params_release(&session->key.ecdh_params); gnutls_pk_params_init(&session->key.ecdh_params); i = 0; DECR_LEN(data_size, 1); if (data[i++] != 3) return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); DECR_LEN(data_size, 2); curve = _gnutls_tls_id_to_ecc_curve(_gnutls_read_uint16(&data[i])); i += 2; ret = _gnutls_session_supports_ecc_curve(session, curve); if (ret < 0) return gnutls_assert_val(ret); _gnutls_session_ecc_curve_set(session, curve); DECR_LEN(data_size, 1); point_size = data[i]; i++; DECR_LEN(data_size, point_size); ret = _gnutls_ecc_ansi_x963_import(&data[i], point_size, &session->key.ecdh_x, &session->key.ecdh_y); if (ret < 0) return gnutls_assert_val(ret); i += point_size; return i; }
/* just read the hint from the server key exchange. */ static int _gnutls_proc_psk_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { ssize_t data_size = _data_size; int ret; gnutls_datum_t hint; gnutls_psk_client_credentials_t cred; psk_auth_info_t info; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if ((ret = _gnutls_auth_info_set(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1)) < 0) { gnutls_assert(); return ret; } DECR_LENGTH_RET(data_size, 2, 0); hint.size = _gnutls_read_uint16(&data[0]); DECR_LEN(data_size, hint.size); hint.data = &data[2]; /* copy the hint to the auth info structures */ info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } if (hint.size > sizeof(info->hint)-1) { gnutls_assert(); return GNUTLS_E_ILLEGAL_SRP_USERNAME; } memcpy(info->hint, hint.data, hint.size); info->hint[hint.size] = 0; ret = 0; return ret; }
int oprfi_recv_client (gnutls_session_t session, const opaque * data, size_t _data_size) { ssize_t data_size = _data_size; uint16_t len; int ret; if (session->security_parameters.extensions.oprfi_client == NULL) { gnutls_assert (); return 0; } DECR_LEN (data_size, 2); len = _gnutls_read_uint16 (data); data += 2; if (len != data_size) { gnutls_assert (); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } if (len != session->security_parameters.extensions.oprfi_client_len) { gnutls_assert (); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } /* Store incoming data. */ session->security_parameters.extensions.oprfi_server_len = len; session->security_parameters.extensions.oprfi_server = gnutls_malloc (len); if (!session->security_parameters.extensions.oprfi_server) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } memcpy (session->security_parameters.extensions.oprfi_server, data, len); return 0; }
/* * In case of a server: if a SUPPORTED_ECC extension type is received then it stores * into the session security parameters the new value. The server may use gnutls_session_certificate_type_get(), * to access it. * * In case of a client: If a supported_eccs have been specified then we send the extension. * */ static int _gnutls_supported_ecc_pf_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { int len, i; int uncompressed = 0; int data_size = _data_size; if (session->security_parameters.entity == GNUTLS_CLIENT) { if (data_size < 1) return gnutls_assert_val (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); len = data[0]; DECR_LEN(data_size, len + 1); for (i = 1; i <= len; i++) if (data[i] == 0) /* uncompressed */ uncompressed = 1; if (uncompressed == 0) return gnutls_assert_val (GNUTLS_E_UNKNOWN_PK_ALGORITHM); } else { /* only sanity check here. We only support uncompressed points * and a client must support it thus nothing to check. */ if (_data_size < 1) return gnutls_assert_val (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); } return 0; }
/* just read A and put it to session */ int _gnutls_proc_srp_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { size_t _n_A; ssize_t data_size = _data_size; int ret; DECR_LEN (data_size, 2); _n_A = _gnutls_read_uint16 (&data[0]); DECR_LEN (data_size, _n_A); if (_gnutls_mpi_scan_nz (&A, &data[2], &_n_A) || A == NULL) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_dump_mpi ("SRP A: ", A); _gnutls_dump_mpi ("SRP B: ", B); /* Checks if A % n == 0. */ if ((ret = check_a_mod_n (A, N)) < 0) { gnutls_assert (); return ret; } /* Start the SRP calculations. * - Calculate u */ session->key->u = _gnutls_calc_srp_u (A, B, N); if (session->key->u == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP U: ", session->key->u); /* S = (A * v^u) ^ b % N */ S = _gnutls_calc_srp_S1 (A, _b, session->key->u, V, N); if (S == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_dump_mpi ("SRP S: ", S); _gnutls_mpi_release (&A); _gnutls_mpi_release (&_b); _gnutls_mpi_release (&V); _gnutls_mpi_release (&session->key->u); _gnutls_mpi_release (&B); ret = _gnutls_mpi_dprint (&session->key->key, session->key->KEY); _gnutls_mpi_release (&S); if (ret < 0) { gnutls_assert (); return ret; } return 0; }
static int proc_psk_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { int bits; int ret; mpi_t p, g; gnutls_dh_params_t dh_params; const mpi_t *mpis; gnutls_psk_server_credentials_t cred; psk_auth_info_t info; gnutls_datum_t username; ssize_t data_size = _data_size; cred = (gnutls_psk_server_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } bits = _gnutls_dh_get_allowed_prime_bits (session); if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_PSK, sizeof (psk_auth_info_st), 1)) < 0) { gnutls_assert (); return ret; } dh_params = _gnutls_get_dh_params (cred->dh_params, cred->params_func, session); mpis = _gnutls_dh_params_to_mpi (dh_params); if (mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_DH_PARAMS; } p = mpis[0]; g = mpis[1]; DECR_LEN (data_size, 2); username.size = _gnutls_read_uint16 (&data[0]); DECR_LEN (data_size, username.size); username.data = &data[2]; /* copy the username to the auth info structures */ info = _gnutls_get_auth_info (session); if (username.size > MAX_SRP_USERNAME) { gnutls_assert (); return GNUTLS_E_ILLEGAL_SRP_USERNAME; } memcpy (info->username, username.data, username.size); info->username[username.size] = 0; /* Adjust the data */ data += username.size + 2; ret = _gnutls_proc_dh_common_client_kx (session, data, data_size, g, p); return ret; }
static int _gnutls_cert_type_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { int new_type = -1, ret, i; ssize_t data_size = _data_size; if (session->security_parameters.entity == GNUTLS_CLIENT) { if (data_size > 0) { if (data_size != 1) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } new_type = _gnutls_num2cert_type(data[0]); if (new_type < 0) { gnutls_assert(); return new_type; } /* Check if we support this cert_type */ if ((ret = _gnutls_session_cert_type_supported(session, new_type)) < 0) { gnutls_assert(); return ret; } _gnutls_session_cert_type_set(session, new_type); } } else { /* SERVER SIDE - we must check if the sent cert type is the right one */ if (data_size > 1) { uint8_t len; DECR_LEN(data_size, 1); len = data[0]; DECR_LEN(data_size, len); for (i = 0; i < len; i++) { new_type = _gnutls_num2cert_type(data[i + 1]); if (new_type < 0) continue; /* Check if we support this cert_type */ if ((ret = _gnutls_session_cert_type_supported (session, new_type)) < 0) { gnutls_assert(); continue; } else break; /* new_type is ok */ } if (new_type < 0) { gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } if ((ret = _gnutls_session_cert_type_supported(session, new_type)) < 0) { gnutls_assert(); /* The peer has requested unsupported certificate * types. Instead of failing, procceed normally. * (the ciphersuite selection would fail, or a * non certificate ciphersuite will be selected). */ return 0; } _gnutls_session_cert_type_set(session, new_type); } } return 0; }
int _gnutls_proc_dh_common_client_kx (gnutls_session_t session, uint8_t * data, size_t _data_size, bigint_t g, bigint_t p, gnutls_datum_t* psk_key) { uint16_t n_Y; size_t _n_Y; int ret; ssize_t data_size = _data_size; DECR_LEN (data_size, 2); n_Y = _gnutls_read_uint16 (&data[0]); _n_Y = n_Y; DECR_LEN (data_size, n_Y); if (_gnutls_mpi_scan_nz (&session->key.client_Y, &data[2], _n_Y)) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_dh_set_peer_public (session, session->key.client_Y); ret = gnutls_calc_dh_key (&session->key.KEY, session->key.client_Y, session->key.dh_secret, p); if (ret < 0) return gnutls_assert_val(ret); _gnutls_mpi_release (&session->key.client_Y); _gnutls_mpi_release (&session->key.dh_secret); if (psk_key == NULL) { ret = _gnutls_mpi_dprint (session->key.KEY, &session->key.key); } else /* In DHE_PSK the key is set differently */ { gnutls_datum_t tmp_dh_key; ret = _gnutls_mpi_dprint (session->key.KEY, &tmp_dh_key); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_set_psk_session_key (session, psk_key, &tmp_dh_key); _gnutls_free_datum (&tmp_dh_key); } _gnutls_mpi_release (&session->key.KEY); if (ret < 0) { return ret; } return 0; }
/* Returns the bytes parsed */ int _gnutls_proc_dh_common_server_kx (gnutls_session_t session, uint8_t * data, size_t _data_size) { uint16_t n_Y, n_g, n_p; size_t _n_Y, _n_g, _n_p; uint8_t *data_p; uint8_t *data_g; uint8_t *data_Y; int i, bits, ret; ssize_t data_size = _data_size; i = 0; DECR_LEN (data_size, 2); n_p = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_p); data_p = &data[i]; i += n_p; DECR_LEN (data_size, 2); n_g = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_g); data_g = &data[i]; i += n_g; DECR_LEN (data_size, 2); n_Y = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_Y); data_Y = &data[i]; _n_Y = n_Y; _n_g = n_g; _n_p = n_p; if (_gnutls_mpi_scan_nz (&session->key.client_Y, data_Y, _n_Y) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&session->key.client_g, data_g, _n_g) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&session->key.client_p, data_p, _n_p) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } bits = _gnutls_dh_get_allowed_prime_bits (session); if (bits < 0) { gnutls_assert (); return bits; } if (_gnutls_mpi_get_nbits (session->key.client_p) < (size_t) bits) { /* the prime used by the peer is not acceptable */ gnutls_assert (); return GNUTLS_E_DH_PRIME_UNACCEPTABLE; } _gnutls_dh_set_group (session, session->key.client_g, session->key.client_p); _gnutls_dh_set_peer_public (session, session->key.client_Y); ret = n_Y + n_p + n_g + 6; return ret; }
static int proc_srp_cert_server_kx (gnutls_session_t session, opaque * data, size_t _data_size) { ssize_t ret; int sigsize; gnutls_datum_t vparams, signature; ssize_t data_size; cert_auth_info_t info; gnutls_cert peer_cert; opaque *p; ret = _gnutls_proc_srp_server_kx (session, data, _data_size); if (ret < 0) return ret; data_size = _data_size - ret; info = _gnutls_get_auth_info (session); if (info == NULL || info->ncerts == 0) { gnutls_assert (); /* we need this in order to get peer's certificate */ return GNUTLS_E_INTERNAL_ERROR; } /* VERIFY SIGNATURE */ vparams.size = ret; /* all the data minus the signature */ vparams.data = data; p = &data[vparams.size]; DECR_LEN (data_size, 2); sigsize = _gnutls_read_uint16 (p); DECR_LEN (data_size, sigsize); signature.data = &p[2]; signature.size = sigsize; ret = _gnutls_get_auth_info_gcert (&peer_cert, session->security_parameters.cert_type, info, CERT_NO_COPY); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_handshake_verify_data (session, &peer_cert, &vparams, &signature, GNUTLS_SIGN_UNKNOWN); _gnutls_gcert_deinit (&peer_cert); if (ret < 0) { gnutls_assert (); return ret; } return 0; }
static int proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; int use_rnd_key = 0; ssize_t data_size = _data_size; gnutls_datum_t rndkey = {NULL, 0}; if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; } else { /* TLS 1.0 */ 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; } rndkey.size = GNUTLS_MASTER_SIZE; rndkey.data = gnutls_malloc(rndkey.size); if (rndkey.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, rndkey.data, rndkey.size); if (ret < 0) { gnutls_assert(); goto cleanup; } 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_debug_log("auth_rsa: Possible PKCS #1 format attack\n"); use_rnd_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_debug_log("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (use_rnd_key != 0) { session->key.key.data = rndkey.data; session->key.key.size = rndkey.size; rndkey.data = NULL; } else { session->key.key.data = plaintext.data; session->key.key.size = plaintext.size; } /* This is here to avoid the version check attack * discussed above. */ session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); ret = 0; cleanup: gnutls_free(rndkey.data); return ret; }
static int parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size) { int len, ret; uint8_t *p = data; cert_auth_info_t info; gnutls_certificate_credentials_t cred; ssize_t dsize = data_size, size; int i; unsigned npeer_certs, npeer_ocsp, j; crt_cert_ctx_st ctx; gnutls_datum_t *peer_certs = NULL; gnutls_datum_t *peer_ocsp = NULL; unsigned nentries = 0; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE, sizeof(cert_auth_info_st), 1)) < 0) { gnutls_assert(); return ret; } if (data == NULL || data_size == 0) { /* no certificate was sent */ return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); DECR_LEN(dsize, 3); size = _gnutls_read_uint24(p); p += 3; if (size != dsize) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (size == 0) return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND); i = dsize; while (i > 0) { DECR_LEN(dsize, 3); len = _gnutls_read_uint24(p); if (len == 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); DECR_LEN(dsize, len); p += len + 3; i -= len + 3; DECR_LEN(dsize, 2); len = _gnutls_read_uint16(p); DECR_LEN(dsize, len); i -= len + 2; p += len + 2; nentries++; } if (dsize != 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); /* this is unnecessary - keeping to avoid a regression due to a re-org * of the loop above */ if (nentries == 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); npeer_ocsp = 0; npeer_certs = 0; /* Ok we now allocate the memory to hold the * certificate list */ peer_certs = gnutls_calloc(nentries, sizeof(gnutls_datum_t)); if (peer_certs == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); peer_ocsp = gnutls_calloc(nentries, sizeof(gnutls_datum_t)); if (peer_ocsp == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto cleanup; } p = data+3; /* Now we start parsing the list (again). * We don't use DECR_LEN since the list has * been parsed before. */ ctx.session = session; for (j = 0; j < nentries; j++) { len = _gnutls_read_uint24(p); p += 3; ret = _gnutls_set_datum(&peer_certs[j], p, len); if (ret < 0) { gnutls_assert(); ret = GNUTLS_E_CERTIFICATE_ERROR; goto cleanup; } npeer_certs++; p += len; len = _gnutls_read_uint16(p); ctx.ocsp = &peer_ocsp[j]; ctx.idx = j; ret = _gnutls_extv_parse(&ctx, parse_cert_extension, p, len+2); if (ret < 0) { gnutls_assert(); goto cleanup; } p += len+2; npeer_ocsp++; } /* The OCSP entries match the certificate entries, although * the contents of each OCSP entry may be NULL. */ for(j=0;j<info->ncerts;j++) gnutls_free(info->raw_certificate_list[j].data); gnutls_free(info->raw_certificate_list); for(j=0;j<info->nocsp;j++) gnutls_free(info->raw_ocsp_list[j].data); gnutls_free(info->raw_ocsp_list); info->raw_certificate_list = peer_certs; info->ncerts = npeer_certs; info->raw_ocsp_list = peer_ocsp; info->nocsp = npeer_ocsp; return 0; cleanup: for(j=0;j<npeer_certs;j++) gnutls_free(peer_certs[j].data); for(j=0;j<npeer_ocsp;j++) gnutls_free(peer_ocsp[j].data); gnutls_free(peer_certs); gnutls_free(peer_ocsp); return ret; }
/* * In case of a server: if a NAME_DNS extension type is received then * it stores into the session the value of NAME_DNS. The server may * use gnutls_ext_get_server_name(), in order to access it. * * In case of a client: If a proper NAME_DNS extension type is found * in the session then it sends the extension to the peer. * */ static int _gnutls_server_name_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { int i; const unsigned char *p; uint16_t len, type; ssize_t data_size = _data_size; int server_names = 0; server_name_ext_st *priv; extension_priv_data_t epriv; if (session->security_parameters.entity == GNUTLS_SERVER) { DECR_LENGTH_RET(data_size, 2, 0); len = _gnutls_read_uint16(data); if (len != data_size) { /* This is unexpected packet length, but * just ignore it, for now. */ gnutls_assert(); return 0; } p = data + 2; /* Count all server_names in the packet. */ while (data_size > 0) { DECR_LENGTH_RET(data_size, 1, 0); p++; DECR_LEN(data_size, 2); len = _gnutls_read_uint16(p); p += 2; if (len > 0) { DECR_LENGTH_RET(data_size, len, 0); server_names++; p += len; } else _gnutls_handshake_log ("HSK[%p]: Received (0) size server name (under attack?)\n", session); } /* we cannot accept more server names. */ if (server_names > MAX_SERVER_NAME_EXTENSIONS) { _gnutls_handshake_log ("HSK[%p]: Too many server names received (under attack?)\n", session); server_names = MAX_SERVER_NAME_EXTENSIONS; } if (server_names == 0) return 0; /* no names found */ priv = gnutls_calloc(1, sizeof(*priv)); if (priv == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } priv->server_names_size = server_names; p = data + 2; for (i = 0; i < server_names; i++) { type = *p; p++; len = _gnutls_read_uint16(p); p += 2; switch (type) { case 0: /* NAME_DNS */ if (len < MAX_SERVER_NAME_SIZE) { memcpy(priv->server_names[i].name, p, len); priv->server_names[i].name[len] = 0; priv->server_names[i].name_length = len; priv->server_names[i].type = GNUTLS_NAME_DNS; break; } } /* move to next record */ p += len; } epriv = priv; _gnutls_ext_set_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, epriv); } return 0; }
static int proc_rsa_export_server_kx (gnutls_session_t session, opaque * data, size_t _data_size) { uint16_t n_m, n_e; size_t _n_m, _n_e; uint8_t *data_m; uint8_t *data_e; int i, sigsize; gnutls_datum_t vparams, signature; int ret; ssize_t data_size = _data_size; cert_auth_info_t info; gnutls_pcert_st peer_cert; info = _gnutls_get_auth_info (session); if (info == NULL || info->ncerts == 0) { gnutls_assert (); /* we need this in order to get peer's certificate */ return GNUTLS_E_INTERNAL_ERROR; } i = 0; DECR_LEN (data_size, 2); n_m = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_m); data_m = &data[i]; i += n_m; DECR_LEN (data_size, 2); n_e = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_e); data_e = &data[i]; i += n_e; _n_e = n_e; _n_m = n_m; if (_gnutls_mpi_scan_nz (&session->key->rsa[0], data_m, _n_m) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&session->key->rsa[1], data_e, _n_e) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_rsa_export_set_pubkey (session, session->key->rsa[1], session->key->rsa[0]); /* VERIFY SIGNATURE */ vparams.size = n_m + n_e + 4; vparams.data = data; DECR_LEN (data_size, 2); sigsize = _gnutls_read_uint16 (&data[vparams.size]); DECR_LEN (data_size, sigsize); signature.data = &data[vparams.size + 2]; signature.size = sigsize; if ((ret = _gnutls_get_auth_info_pcert (&peer_cert, session->security_parameters.cert_type, info)) < 0) { gnutls_assert (); return ret; } ret = _gnutls_handshake_verify_data (session, &peer_cert, &vparams, &signature, GNUTLS_SIGN_UNKNOWN); gnutls_pcert_deinit (&peer_cert); if (ret < 0) { gnutls_assert (); } return ret; }
int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; bigint_t *params; int params_len; int randomize_key = 0; ssize_t data_size = _data_size; if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; } else { /* TLS 1.0 */ 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_get_private_rsa_params (session, ¶ms, ¶ms_len); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */ 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_audit_log ("auth_rsa: 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] || _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_audit_log ("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (randomize_key != 0) { session->key->key.size = GNUTLS_MASTER_SIZE; session->key->key.data = gnutls_malloc (session->key->key.size); if (session->key->key.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data, session->key->key.size); if (ret < 0) { gnutls_assert (); return ret; } } else { session->key->key.data = plaintext.data; session->key->key.size = plaintext.size; } /* This is here to avoid the version check attack * discussed above. */ session->key->key.data[0] = _gnutls_get_adv_version_major (session); session->key->key.data[1] = _gnutls_get_adv_version_minor (session); return 0; }
static int proc_srp_cert_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { ssize_t ret; int sigsize; gnutls_datum_t vparams, signature; ssize_t data_size; cert_auth_info_t info; gnutls_pcert_st peer_cert; uint8_t *p; gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN; const version_entry_st *ver = get_version(session); if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ret = _gnutls_proc_srp_server_kx(session, data, _data_size); if (ret < 0) return ret; data_size = _data_size - ret; info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); if (info == NULL || info->ncerts == 0) { gnutls_assert(); /* we need this in order to get peer's certificate */ return GNUTLS_E_INTERNAL_ERROR; } /* VERIFY SIGNATURE */ vparams.size = ret; /* all the data minus the signature */ vparams.data = data; p = &data[vparams.size]; if (_gnutls_version_has_selectable_sighash(ver)) { sign_algorithm_st aid; DECR_LEN(data_size, 1); aid.hash_algorithm = *p++; DECR_LEN(data_size, 1); aid.sign_algorithm = *p++; sign_algo = _gnutls_tls_aid_to_sign(&aid); if (sign_algo == GNUTLS_SIGN_UNKNOWN) { _gnutls_debug_log("unknown signature %d.%d\n", aid.sign_algorithm, aid.hash_algorithm); gnutls_assert(); return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM; } } DECR_LEN(data_size, 2); sigsize = _gnutls_read_uint16(p); DECR_LEN(data_size, sigsize); signature.data = &p[2]; signature.size = sigsize; ret = _gnutls_get_auth_info_pcert(&peer_cert, session->security_parameters. cert_type, info); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_handshake_verify_data(session, &peer_cert, &vparams, &signature, sign_algo); gnutls_pcert_deinit(&peer_cert); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
static int _gnutls_srtp_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { unsigned int i; int ret; const uint8_t *p = data; int len; ssize_t data_size = _data_size; srtp_ext_st *priv; extension_priv_data_t epriv; uint16_t profile; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRTP, &epriv); if (ret < 0) return 0; priv = epriv; DECR_LENGTH_RET(data_size, 2, 0); len = _gnutls_read_uint16(p); p += 2; if (len + 1 > data_size) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (session->security_parameters.entity == GNUTLS_SERVER) { if (len > MAX_PROFILES_IN_SRTP_EXTENSION * 2) return 0; } else { if (len != 2) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } priv->selected_profile = 0; while (len > 0) { DECR_LEN(data_size, 2); profile = _gnutls_read_uint16(p); for (i = 0; i < priv->profiles_size && priv->selected_profile == 0; i++) { if (priv->profiles[i] == profile) { priv->selected_profile = profile; break; } } p += 2; len -= 2; } DECR_LEN(data_size, 1); priv->mki_size = *p; p++; if (priv->mki_size > 0) { DECR_LEN(data_size, priv->mki_size); memcpy(priv->mki, p, priv->mki_size); priv->mki_received = 1; } return 0; }
/* receive the key exchange message ( n, g, s, B) */ int _gnutls_proc_srp_server_kx (gnutls_session_t session, opaque * data, size_t _data_size) { uint8_t n_s; uint16_t n_g, n_n, n_b; size_t _n_s, _n_g, _n_n, _n_b; const uint8_t *data_n; const uint8_t *data_g; const uint8_t *data_s; const uint8_t *data_b; int i, ret; opaque hd[SRP_MAX_HASH_SIZE]; char *username, *password; ssize_t data_size = _data_size; gnutls_srp_client_credentials_t cred; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_SRP, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (session->internals.srp_username == NULL) { username = cred->username; password = cred->password; } else { username = session->internals.srp_username; password = session->internals.srp_password; } if (username == NULL || password == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } i = 0; /* Read N */ DECR_LEN (data_size, 2); n_n = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_n); data_n = &data[i]; i += n_n; /* Read G */ DECR_LEN (data_size, 2); n_g = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_g); data_g = &data[i]; i += n_g; /* Read salt */ DECR_LEN (data_size, 1); n_s = data[i]; i += 1; DECR_LEN (data_size, n_s); data_s = &data[i]; i += n_s; /* Read B */ DECR_LEN (data_size, 2); n_b = _gnutls_read_uint16 (&data[i]); i += 2; DECR_LEN (data_size, n_b); data_b = &data[i]; i += n_b; _n_s = n_s; _n_g = n_g; _n_n = n_n; _n_b = n_b; if (_gnutls_mpi_scan_nz (&N, data_n, &_n_n) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&G, data_g, &_n_g) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_scan_nz (&B, data_b, &_n_b) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } /* Check if the g and n are from the SRP * draft. Otherwise check if N is a prime and G * a generator. */ if ((ret = check_g_n (data_g, _n_g, data_n, _n_n)) < 0) { _gnutls_x509_log ("Checking the SRP group parameters.\n"); if ((ret = group_check_g_n (G, N)) < 0) { gnutls_assert (); return ret; } } /* Checks if b % n == 0 */ if ((ret = check_b_mod_n (B, N)) < 0) { gnutls_assert (); return ret; } /* generate x = SHA(s | SHA(U | ":" | p)) * (or the equivalent using bcrypt) */ if ((ret = _gnutls_calc_srp_x (username, password, (opaque *) data_s, n_s, &_n_g, hd)) < 0) { gnutls_assert (); return ret; } if (_gnutls_mpi_scan_nz (&session->key->x, hd, &_n_g) != 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } return i; /* return the processed data * needed in auth_srp_rsa. */ }
/* Read a v2 client hello. Some browsers still use that beast! * However they set their version to 3.0 or 3.1. */ int _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, unsigned int datalen) { uint16_t session_id_len = 0; int pos = 0; int ret = 0, sret = 0; uint16_t sizeOfSuites; gnutls_protocol_t adv_version; uint8_t rnd[GNUTLS_RANDOM_SIZE]; int len = datalen; uint16_t challenge; uint8_t session_id[GNUTLS_MAX_SESSION_ID_SIZE]; DECR_LEN(len, 2); _gnutls_handshake_log ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session, data[pos], data[pos + 1]); set_adv_version(session, data[pos], data[pos + 1]); adv_version = _gnutls_version_get(data[pos], data[pos + 1]); ret = _gnutls_negotiate_version(session, adv_version); if (ret < 0) { gnutls_assert(); return ret; } pos += 2; /* Read uint16_t cipher_spec_length */ DECR_LEN(len, 2); sizeOfSuites = _gnutls_read_uint16(&data[pos]); pos += 2; /* read session id length */ DECR_LEN(len, 2); session_id_len = _gnutls_read_uint16(&data[pos]); pos += 2; if (session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } /* read challenge length */ DECR_LEN(len, 2); challenge = _gnutls_read_uint16(&data[pos]); pos += 2; if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE) { gnutls_assert(); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; } /* call the user hello callback */ ret = _gnutls_user_hello_func(session, adv_version); if (ret < 0) { if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { sret = GNUTLS_E_INT_RET_0; } else { gnutls_assert(); return ret; } } /* find an appropriate cipher suite */ DECR_LEN(len, sizeOfSuites); ret = _gnutls_handshake_select_v2_suite(session, &data[pos], sizeOfSuites); pos += sizeOfSuites; if (ret < 0) { gnutls_assert(); return ret; } /* check if the credentials (username, public key etc.) are ok */ if (_gnutls_get_kx_cred (session, _gnutls_cipher_suite_get_kx_algo(session->security_parameters. cipher_suite)) == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* set the mod_auth_st to the appropriate struct * according to the KX algorithm. This is needed since all the * handshake functions are read from there; */ session->internals.auth_struct = _gnutls_kx_auth_struct(_gnutls_cipher_suite_get_kx_algo (session->security_parameters. cipher_suite)); if (session->internals.auth_struct == NULL) { _gnutls_handshake_log ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n", session); gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } /* read random new values -skip session id for now */ DECR_LEN(len, session_id_len); /* skip session id for now */ memcpy(session_id, &data[pos], session_id_len); pos += session_id_len; DECR_LEN(len, challenge); memset(rnd, 0, GNUTLS_RANDOM_SIZE); memcpy(&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos], challenge); ret = _gnutls_set_client_random(session, rnd); if (ret < 0) return gnutls_assert_val(ret); /* generate server random value */ ret = _gnutls_set_server_random(session, NULL); if (ret < 0) return gnutls_assert_val(ret); session->security_parameters.timestamp = gnutls_time(NULL); /* RESUME SESSION */ DECR_LEN(len, session_id_len); ret = _gnutls_server_restore_session(session, session_id, session_id_len); if (ret == 0) { /* resumed! */ /* get the new random values */ memcpy(session->internals.resumed_security_parameters. server_random, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy(session->internals.resumed_security_parameters. client_random, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); session->internals.resumed = RESUME_TRUE; return 0; } else { _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); session->internals.resumed = RESUME_FALSE; } _gnutls_epoch_set_compression(session, EPOCH_NEXT, GNUTLS_COMP_NULL); session->security_parameters.compression_method = GNUTLS_COMP_NULL; return sret; }
/* receive the key exchange message ( n, g, s, B) */ int _gnutls_proc_srp_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { uint8_t n_s; uint16_t n_g, n_n, n_b; size_t _n_g, _n_n, _n_b; const uint8_t *data_n; const uint8_t *data_g; const uint8_t *data_s; const uint8_t *data_b; int i, ret; uint8_t hd[SRP_MAX_HASH_SIZE]; char *username, *password; ssize_t data_size = _data_size; gnutls_srp_client_credentials_t cred; extension_priv_data_t epriv; srp_ext_st *priv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRP, &epriv); if (ret < 0) { gnutls_assert(); return GNUTLS_E_UNKNOWN_SRP_USERNAME; } priv = epriv; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_SRP); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (priv->username == NULL) { username = cred->username; password = cred->password; } else { username = priv->username; password = priv->password; } if (username == NULL || password == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } i = 0; /* Read N */ DECR_LEN(data_size, 2); n_n = _gnutls_read_uint16(&data[i]); i += 2; DECR_LEN(data_size, n_n); data_n = &data[i]; i += n_n; /* Read G */ DECR_LEN(data_size, 2); n_g = _gnutls_read_uint16(&data[i]); i += 2; DECR_LEN(data_size, n_g); data_g = &data[i]; i += n_g; /* Read salt */ DECR_LEN(data_size, 1); n_s = data[i]; i += 1; DECR_LEN(data_size, n_s); data_s = &data[i]; i += n_s; /* Read B */ DECR_LEN(data_size, 2); n_b = _gnutls_read_uint16(&data[i]); i += 2; DECR_LEN(data_size, n_b); data_b = &data[i]; i += n_b; _n_g = n_g; _n_n = n_n; _n_b = n_b; if (_gnutls_mpi_init_scan_nz(&N, data_n, _n_n) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_init_scan_nz(&G, data_g, _n_g) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_init_scan_nz(&B, data_b, _n_b) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } /* Check if the g and n are from the SRP * draft. Otherwise check if N is a prime and G * a generator. */ if ((ret = check_g_n(data_g, _n_g, data_n, _n_n)) < 0) { _gnutls_audit_log(session, "SRP group parameters are not in the white list. Checking validity.\n"); if ((ret = group_check_g_n(session, G, N)) < 0) { gnutls_assert(); return ret; } } /* Checks if b % n == 0 */ if ((ret = check_param_mod_n(B, N, 0)) < 0) { gnutls_assert(); return ret; } /* generate x = SHA(s | SHA(U | ":" | p)) * (or the equivalent using bcrypt) */ if ((ret = _gnutls_calc_srp_x(username, password, (uint8_t *) data_s, n_s, &_n_g, hd)) < 0) { gnutls_assert(); return ret; } if (_gnutls_mpi_init_scan_nz(&session->key.x, hd, _n_g) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } return i; /* return the processed data * needed in auth_srp_rsa. */ }
/* 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_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); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } ret = _gnutls_auth_info_init(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, username.size); username.data = &data[2]; /* copy the username to the auth info structures */ info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); if (info == NULL) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } 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; /* 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 formatting). */ gnutls_assert(); _gnutls_debug_log ("auth_rsa_psk: Possible PKCS #1 format attack\n"); if (ret >= 0) { gnutls_free(plaintext.data); } 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.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_key_datum(&pwd_psk); _gnutls_free_temp_key_datum(&premaster_secret); return ret; }
/* * In case of a server: if a SUPPORTED_ECC extension type is received then it stores * into the session security parameters the new value. The server may use gnutls_session_certificate_type_get(), * to access it. * * In case of a client: If a supported_eccs have been specified then we send the extension. * */ static int _gnutls_supported_ecc_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { int new_type = -1, ret, i; ssize_t data_size = _data_size; uint16_t len; const uint8_t *p = data; if (session->security_parameters.entity == GNUTLS_CLIENT) { /* A client shouldn't receive this extension, but of course * there are servers out there that send it. Just ignore it. */ _gnutls_debug_log("received SUPPORTED ECC extension on client side!!!\n"); return 0; } else { /* SERVER SIDE - we must check if the sent supported ecc type is the right one */ if (data_size < 2) return gnutls_assert_val (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); DECR_LEN(data_size, 2); len = _gnutls_read_uint16(p); p += 2; if (len % 2 != 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); DECR_LEN(data_size, len); for (i = 0; i < len; i += 2) { new_type = _gnutls_tls_id_to_ecc_curve(_gnutls_read_uint16 (&p[i])); if (new_type < 0) continue; /* Check if we support this supported_ecc */ if ((ret = _gnutls_session_supports_ecc_curve(session, new_type)) < 0) { continue; } else break; /* new_type is ok */ } if (new_type < 0) { gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } if ((ret = _gnutls_session_supports_ecc_curve(session, new_type)) < 0) { /* The peer has requested unsupported ecc * types. Instead of failing, procceed normally. * (the ciphersuite selection would fail, or a * non certificate ciphersuite will be selected). */ return gnutls_assert_val(0); } _gnutls_session_ecc_curve_set(session, new_type); } return 0; }
static int proc_dhe_server_kx (gnutls_session_t session, opaque * data, size_t _data_size) { int sigsize; opaque *sigdata; gnutls_datum_t vparams, signature; int ret; cert_auth_info_t info = _gnutls_get_auth_info (session); ssize_t data_size = _data_size; gnutls_cert peer_cert; gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN; gnutls_protocol_t ver = gnutls_protocol_get_version (session); if (info == NULL || info->ncerts == 0) { gnutls_assert (); /* we need this in order to get peer's certificate */ return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_proc_dh_common_server_kx (session, data, _data_size, 0); if (ret < 0) { gnutls_assert (); return ret; } /* VERIFY SIGNATURE */ vparams.size = ret; vparams.data = data; sigdata = &data[vparams.size]; if (_gnutls_version_has_selectable_sighash (ver)) { sign_algorithm_st aid; DECR_LEN (data_size, 1); aid.hash_algorithm = *sigdata++; DECR_LEN (data_size, 1); aid.sign_algorithm = *sigdata++; sign_algo = _gnutls_tls_aid_to_sign (&aid); if (sign_algo == GNUTLS_SIGN_UNKNOWN) { gnutls_assert (); return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM; } } DECR_LEN (data_size, 2); sigsize = _gnutls_read_uint16 (sigdata); sigdata += 2; DECR_LEN (data_size, sigsize); signature.data = sigdata; signature.size = sigsize; if ((ret = _gnutls_get_auth_info_gcert (&peer_cert, session->security_parameters.cert_type, info, CERT_NO_COPY)) < 0) { gnutls_assert (); return ret; } ret = _gnutls_handshake_verify_data (session, &peer_cert, &vparams, &signature, sign_algo); _gnutls_gcert_deinit (&peer_cert); if (ret < 0) { gnutls_assert (); return ret; } return ret; }
static int _proxyinfo_recv_params (gnutls_session_t session, const opaque * data, size_t _data_size) { //printf("Recv params\n"); int i; const unsigned char *p; uint16_t len, type; ssize_t data_size = _data_size; int server_names = 0; ProxyInfo_ext_st *priv; extension_priv_data_t epriv; if (session->security_parameters.entity == GNUTLS_SERVER) { DECR_LENGTH_RET (data_size, 2, 0); len = _gnutls_read_uint16 (data); if (len != data_size) { /* This is unexpected packet length, but * just ignore it, for now. */ gnutls_assert (); return 0; } p = data + 2; DECR_LEN (data_size, 2); unsigned count = _gnutls_read_uint16 (p); p+=2; printf("Received Proxy_Info for %d intermediate proxies\n",count+1); priv = gnutls_calloc (1, sizeof (*priv)); if (priv == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } priv->proxy_cnt=count; for (int proxy_id=0;proxy_id<count+1;proxy_id++){ DECR_LEN (data_size, 2); unsigned cipher_algo = _gnutls_read_uint16 (p); p+=2; DECR_LEN (data_size, 2); unsigned kx_algo = _gnutls_read_uint16 (p); p+=2; DECR_LEN (data_size, 2); unsigned mac_algo = _gnutls_read_uint16 (p); p+=2; DECR_LEN (data_size, 2); unsigned ip_addr = _gnutls_read_uint16 (p); p+=2; DECR_LEN (data_size, 2); unsigned mac_addr = _gnutls_read_uint16 (p); p+=2; //printf("%d %d %d %d %d\n",cipher_algo,kx_algo,mac_algo,ip_addr,mac_addr); priv->proxy_info[proxy_id].cipher_algo=cipher_algo; priv->proxy_info[proxy_id].kx_algo=kx_algo; priv->proxy_info[proxy_id].mac_algo=mac_algo; priv->proxy_info[proxy_id].ip_addr=ip_addr; priv->proxy_info[proxy_id].mac_addr=mac_addr; } printf("Stored the proxy_info to local instance of extension...\n"); /* Count all server_names in the packet. */ while (data_size > 0) { DECR_LENGTH_RET (data_size, 1, 0); p++; DECR_LEN (data_size, 2); len = _gnutls_read_uint16 (p); p += 2; if (len > 0) { DECR_LENGTH_RET (data_size, len, 0); server_names++; p += len; } else _gnutls_handshake_log ("HSK[%p]: Received (0) size server name (under attack?)\n", session); } /* we cannot accept more server names. */ if (server_names > MAX_SERVER_NAME_EXTENSIONS) { _gnutls_handshake_log ("HSK[%p]: Too many server names received (under attack?)\n", session); server_names = MAX_SERVER_NAME_EXTENSIONS; } if (server_names == 0) return 0; /* no names found */ priv->server_names_size = server_names; p = data + 4; p+=10*(count+1); for (i = 0; i < server_names; i++) { type = *p; p++; len = _gnutls_read_uint16 (p); p += 2; switch (type) { case 0: /* NAME_DNS */ if (len <= MAX_SERVER_NAME_SIZE) { memcpy (priv->server_names[i].name, p, len); priv->server_names[i].name_length = len; priv->server_names[i].type = GNUTLS_NAME_DNS; break; } } /* move to next record */ p += len; } epriv.ptr = priv; _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_PROXYINFO, epriv); } return 0; }