int _gnutls_parse_extensions(gnutls_session_t session, gnutls_ext_parse_type_t parse_type, const uint8_t * data, int data_size) { int next, ret; int pos = 0; uint16_t type; const uint8_t *sdata; gnutls_ext_recv_func ext_recv; uint16_t size; #ifdef DEBUG int i; if (session->security_parameters.entity == GNUTLS_CLIENT) for (i = 0; i < session->internals.extensions_sent_size; i++) { _gnutls_handshake_log ("EXT[%d]: expecting extension '%s'\n", session, _gnutls_extension_get_name(session->internals. extensions_sent [i])); } #endif DECR_LENGTH_RET(data_size, 2, 0); next = _gnutls_read_uint16(data); pos += 2; DECR_LENGTH_RET(data_size, next, 0); do { DECR_LENGTH_RET(next, 2, 0); type = _gnutls_read_uint16(&data[pos]); pos += 2; if (session->security_parameters.entity == GNUTLS_CLIENT) { if ((ret = _gnutls_extension_list_check(session, type)) < 0) { gnutls_assert(); return ret; } } else { _gnutls_extension_list_add(session, type); } DECR_LENGTH_RET(next, 2, 0); size = _gnutls_read_uint16(&data[pos]); pos += 2; DECR_LENGTH_RET(next, size, 0); sdata = &data[pos]; pos += size; ext_recv = _gnutls_ext_func_recv(type, parse_type); if (ext_recv == NULL) { _gnutls_handshake_log ("EXT[%p]: Found extension '%s/%d'\n", session, _gnutls_extension_get_name(type), type); continue; } _gnutls_handshake_log ("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n", session, _gnutls_extension_get_name(type), type, size); if ((ret = ext_recv(session, sdata, size)) < 0) { gnutls_assert(); return ret; } } while (next > 2); return 0; }
/* 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], major, minor; 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]); major = data[pos]; minor = data[pos + 1]; set_adv_version(session, major, minor); adv_version = _gnutls_version_get(major, minor); ret = _gnutls_negotiate_version(session, adv_version, major, minor); 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, major, minor); 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; } ret = _gnutls_set_compression(session, GNUTLS_COMP_NULL); if (ret < 0) return gnutls_assert_val(ret); return sret; }
/* * Processes a heartbeat message. */ int _gnutls_heartbeat_handle(gnutls_session_t session, mbuffer_st * bufel) { int ret; unsigned type; unsigned pos; uint8_t *msg = _mbuffer_get_udata_ptr(bufel); size_t hb_len, len = _mbuffer_get_udata_size(bufel); if (gnutls_heartbeat_allowed (session, GNUTLS_HB_PEER_ALLOWED_TO_SEND) == 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); if (len < 4) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); pos = 0; type = msg[pos++]; hb_len = _gnutls_read_uint16(&msg[pos]); if (hb_len > len - 3) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); pos += 2; switch (type) { case HEARTBEAT_REQUEST: _gnutls_buffer_reset(&session->internals.hb_remote_data); ret = _gnutls_buffer_resize(&session->internals. hb_remote_data, hb_len); if (ret < 0) return gnutls_assert_val(ret); if (hb_len > 0) memcpy(session->internals.hb_remote_data.data, &msg[pos], hb_len); session->internals.hb_remote_data.length = hb_len; return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PING_RECEIVED); case HEARTBEAT_RESPONSE: if (hb_len != session->internals.hb_local_data.length) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); if (hb_len > 0 && memcmp(&msg[pos], session->internals.hb_local_data.data, hb_len) != 0) { if (IS_DTLS(session)) return gnutls_assert_val(GNUTLS_E_AGAIN); /* ignore it */ else return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET); } _gnutls_buffer_reset(&session->internals.hb_local_data); return gnutls_assert_val(GNUTLS_E_HEARTBEAT_PONG_RECEIVED); default: _gnutls_record_log ("REC[%p]: HB: received unknown type %u\n", session, type); return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); } }
/* * Return zero if session tickets haven't been enabled. */ int _gnutls_recv_new_session_ticket(gnutls_session_t session) { uint8_t *p; int data_size; gnutls_buffer_st buf; uint16_t ticket_len; int ret; session_ticket_ext_st *priv = NULL; gnutls_ext_priv_data_t epriv; if (session->internals.flags & GNUTLS_NO_TICKETS) return 0; if (!session->internals.session_ticket_renew) return 0; /* This is the last flight and peer cannot be sure * we have received it unless we notify him. So we * wait for a message and retransmit if needed. */ if (IS_DTLS(session) && !_dtls_is_async(session)) { unsigned have; mbuffer_st *bufel = NULL; have = gnutls_record_check_pending(session) + record_check_unprocessed(session); if (have != 0) { bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL); } if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) { ret = _dtls_wait_and_retransmit(session); if (ret < 0) return gnutls_assert_val(ret); } } ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 0, &buf); if (ret < 0) return gnutls_assert_val_fatal(ret); p = buf.data; data_size = buf.length; DECR_LENGTH_COM(data_size, 4, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); /* skip over lifetime hint */ p += 4; DECR_LENGTH_COM(data_size, 2, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); ticket_len = _gnutls_read_uint16(p); p += 2; DECR_LENGTH_COM(data_size, ticket_len, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); priv = gnutls_calloc(1, sizeof(*priv)); if (!priv) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } priv->session_ticket = gnutls_realloc_fast(priv->session_ticket, ticket_len); if (!priv->session_ticket) { gnutls_free(priv); gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } memcpy(priv->session_ticket, p, ticket_len); priv->session_ticket_len = ticket_len; epriv = priv; /* Discard the current session ID. (RFC5077 3.4) */ ret = _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); if (ret < 0) { gnutls_assert(); session_ticket_deinit_data(epriv); ret = GNUTLS_E_INTERNAL_ERROR; goto error; } ret = 0; _gnutls_handshake_log ("HSK[%p]: received session ticket\n", session); session->internals.hsk_flags |= HSK_TICKET_RECEIVED; _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_SESSION_TICKET, epriv); error: _gnutls_buffer_clear(&buf); return ret; }
static int session_ticket_recv_params(gnutls_session_t session, const uint8_t * data, size_t _data_size) { ssize_t data_size = _data_size; session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; int ret; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv); if (ret < 0) { return 0; } priv = epriv; if (!priv->session_ticket_enable) return 0; if (session->security_parameters.entity == GNUTLS_SERVER) { struct ticket_st ticket; const uint8_t *encrypted_state; /* The client requested a new session ticket. */ if (data_size == 0) { priv->session_ticket_renew = 1; return 0; } /* Format: * Key name * IV * data length * encrypted data * MAC */ DECR_LEN(data_size, KEY_NAME_SIZE); memcpy(ticket.key_name, data, KEY_NAME_SIZE); data += KEY_NAME_SIZE; /* If the key name of the ticket does not match the one that we hold, issue a new ticket. */ if (memcmp (ticket.key_name, &priv->key[NAME_POS], KEY_NAME_SIZE)) { priv->session_ticket_renew = 1; return 0; } DECR_LEN(data_size, IV_SIZE); memcpy(ticket.IV, data, IV_SIZE); data += 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, MAC_SIZE); memcpy(ticket.mac, data, 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); ret = decrypt_ticket(session, priv, &ticket); gnutls_free(ticket.encrypted_state); ticket.encrypted_state = NULL; if (ret < 0) { priv->session_ticket_renew = 1; return 0; } } else { /* Client */ if (data_size == 0) { priv->session_ticket_renew = 1; return 0; } } 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 unpack_ticket(gnutls_session_t session, gnutls_datum_t *packed, tls13_ticket_st *data) { uint32_t age_add, lifetime; struct timespec creation_time; uint8_t resumption_master_secret[MAX_HASH_SIZE]; size_t resumption_master_secret_size; uint8_t nonce[UINT8_MAX]; size_t nonce_size; gnutls_datum_t state; gnutls_mac_algorithm_t kdf; const mac_entry_st *prf; uint8_t *p; ssize_t len; uint64_t v; int ret; if (unlikely(packed == NULL || data == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); memset(data, 0, sizeof(*data)); p = packed->data; len = packed->size; DECR_LEN(len, 2); kdf = _gnutls_read_uint16(p); p += 2; /* Check if the MAC ID we got is valid */ prf = _gnutls_mac_to_entry(kdf); if (prf == NULL) return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); /* Read the ticket age add and the ticket lifetime */ DECR_LEN(len, 4); age_add = _gnutls_read_uint32(p); p += 4; DECR_LEN(len, 4); lifetime = _gnutls_read_uint32(p); p += 4; /* * Check if the whole ticket is large enough, * and read the resumption master secret */ DECR_LEN(len, 1); resumption_master_secret_size = *p; p += 1; /* Check if the size of resumption_master_secret matches the PRF */ if (resumption_master_secret_size != prf->output_size) return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); DECR_LEN(len, resumption_master_secret_size); memcpy(resumption_master_secret, p, resumption_master_secret_size); p += resumption_master_secret_size; /* Read the ticket nonce */ DECR_LEN(len, 1); nonce_size = *p; p += 1; DECR_LEN(len, nonce_size); memcpy(nonce, p, nonce_size); p += nonce_size; DECR_LEN(len, 2); state.size = _gnutls_read_uint16(p); p += 2; DECR_LEN(len, state.size); state.data = p; p += state.size; DECR_LEN(len, 12); v = _gnutls_read_uint32(p); p += 4; creation_time.tv_sec = (v << 32) | _gnutls_read_uint32(p); p += 4; creation_time.tv_nsec = _gnutls_read_uint32(p); ret = _gnutls_session_unpack(session, &state); if (ret < 0) return gnutls_assert_val(ret); /* No errors - Now return all the data to the caller */ data->prf = prf; memcpy(data->resumption_master_secret, resumption_master_secret, resumption_master_secret_size); memcpy(data->nonce, nonce, nonce_size); data->nonce_size = nonce_size; data->age_add = age_add; data->lifetime = lifetime; memcpy(&data->creation_time, &creation_time, sizeof(struct timespec)); 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]; i += n_Y; _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; }
/* 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, opaque * data, int datalen) { uint16_t session_id_len = 0; int pos = 0; int ret = 0; uint16_t sizeOfSuites; gnutls_protocol_t version; opaque rnd[TLS_RANDOM_SIZE]; int len = datalen; int err; uint16_t challenge; opaque session_id[TLS_MAX_SESSION_ID_SIZE]; gnutls_protocol_t ver; /* we only want to get here once - only in client hello */ session->internals.v2_hello = 0; DECR_LEN (len, 2); _gnutls_handshake_log ("HSK[%x]: 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]); version = _gnutls_version_get (data[pos], data[pos + 1]); /* if we do not support that version */ if (_gnutls_version_is_supported (session, version) == 0) { ver = _gnutls_version_lowest (session); } else { ver = version; } _gnutls_set_current_version (session, ver); 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 > TLS_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 > TLS_RANDOM_SIZE) { gnutls_assert (); return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; } /* 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. current_cipher_suite), &err) == NULL && err != 0) { 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. current_cipher_suite)); if (session->internals.auth_struct == NULL) { _gnutls_handshake_log ("HSK[%x]: 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, TLS_RANDOM_SIZE); memcpy (&rnd[TLS_RANDOM_SIZE - challenge], &data[pos], challenge); _gnutls_set_client_random (session, rnd); /* generate server random value */ _gnutls_tls_create_random (rnd); _gnutls_set_server_random (session, rnd); session->security_parameters.timestamp = 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, TLS_RANDOM_SIZE); memcpy (session->internals.resumed_security_parameters. client_random, session->security_parameters.client_random, TLS_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; } session->internals.compression_method = GNUTLS_COMP_NULL; return 0; }
int _gnutls_proc_rsa_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_x509_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_x509_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; }
/* 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.ptr; 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. */ }
/* just read A and put it to session */ int _gnutls_proc_srp_client_kx(gnutls_session_t session, uint8_t * 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_init_scan_nz(&A, &data[2], _n_A) || A == NULL) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_mpi_log("SRP A: ", A); _gnutls_mpi_log("SRP B: ", B); /* Checks if A % n == 0. */ if ((ret = check_param_mod_n(A, N, 1)) < 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_mpi_log("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_mpi_log("SRP S: ", S); _gnutls_mpi_release(&A); zrelease_temp_mpi_key(&_b); zrelease_temp_mpi_key(&V); zrelease_temp_mpi_key(&session->key.u); zrelease_temp_mpi_key(&B); ret = _gnutls_mpi_dprint(session->key.srp_key, &session->key.key); zrelease_temp_mpi_key(&S); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
int _gnutls_recv_new_session_ticket(gnutls_session_t session) { uint8_t *p; int data_size; gnutls_buffer_st buf; uint16_t ticket_len; int ret; session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv); if (ret < 0) { gnutls_assert(); return 0; } priv = epriv; if (!priv->session_ticket_renew) return 0; /* This is the last flight and peer cannot be sure * we have received it unless we notify him. So we * wait for a message and retransmit if needed. */ if (IS_DTLS(session) && !_dtls_is_async(session) && (gnutls_record_check_pending(session) + record_check_unprocessed(session)) == 0) { ret = _dtls_wait_and_retransmit(session); if (ret < 0) return gnutls_assert_val(ret); } ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 0, &buf); if (ret < 0) return gnutls_assert_val_fatal(ret); p = buf.data; data_size = buf.length; DECR_LENGTH_COM(data_size, 4, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); /* skip over lifetime hint */ p += 4; DECR_LENGTH_COM(data_size, 2, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); ticket_len = _gnutls_read_uint16(p); p += 2; DECR_LENGTH_COM(data_size, ticket_len, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error); priv->session_ticket = gnutls_realloc_fast(priv->session_ticket, ticket_len); if (!priv->session_ticket) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto error; } memcpy(priv->session_ticket, p, ticket_len); priv->session_ticket_len = ticket_len; /* Discard the current session ID. (RFC5077 3.4) */ ret = _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); if (ret < 0) { gnutls_assert(); gnutls_free(priv->session_ticket); priv->session_ticket = NULL; ret = GNUTLS_E_INTERNAL_ERROR; goto error; } ret = 0; error: _gnutls_buffer_clear(&buf); 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.ptr = priv; _gnutls_ext_set_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, epriv); } return 0; }
static int parse_handshake_header (gnutls_session_t session, mbuffer_st* bufel, gnutls_handshake_description_t htype, handshake_buffer_st* hsk) { uint8_t *dataptr = NULL; /* for realloc */ size_t handshake_header_size = HANDSHAKE_HEADER_SIZE(session), data_size; /* Note: SSL2_HEADERS == 1 */ if (_mbuffer_get_udata_size(bufel) < handshake_header_size) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); dataptr = _mbuffer_get_udata_ptr(bufel); /* if reading a client hello of SSLv2 */ if (!IS_DTLS(session) && htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2) { handshake_header_size = SSL2_HEADERS; /* we've already read one byte */ hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */ if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2; hsk->sequence = 0; hsk->start_offset = 0; hsk->end_offset = hsk->length; } else /* TLS handshake headers */ { hsk->htype = dataptr[0]; /* we do not use DECR_LEN because we know * that the packet has enough data. */ hsk->length = _gnutls_read_uint24 (&dataptr[1]); handshake_header_size = HANDSHAKE_HEADER_SIZE(session); if (IS_DTLS(session)) { hsk->sequence = _gnutls_read_uint16 (&dataptr[4]); hsk->start_offset = _gnutls_read_uint24 (&dataptr[6]); hsk->end_offset = hsk->start_offset + _gnutls_read_uint24 (&dataptr[9]); } else { hsk->sequence = 0; hsk->start_offset = 0; hsk->end_offset = hsk->length; } } data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* make the length offset */ if (hsk->end_offset > 0) hsk->end_offset--; _gnutls_handshake_log ("HSK[%p]: %s was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n", session, _gnutls_handshake2str (hsk->htype), (int) hsk->length, (int)data_size, hsk->start_offset, hsk->end_offset-hsk->start_offset+1, (int)hsk->sequence); hsk->header_size = handshake_header_size; memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel), handshake_header_size); if (hsk->length > 0 && (hsk->end_offset-hsk->start_offset >= data_size)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (hsk->length > 0 && (hsk->start_offset >= hsk->end_offset || hsk->end_offset-hsk->start_offset >= data_size || hsk->end_offset >= hsk->length)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); else if (hsk->length == 0 && hsk->end_offset != 0 && hsk->start_offset != 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); return handshake_header_size; }
/* Checks the record headers and returns the length, version and * content type. */ static void record_read_headers(gnutls_session_t session, uint8_t headers[MAX_RECORD_HEADER_SIZE], content_type_t type, gnutls_handshake_description_t htype, struct tls_record_st *record) { /* Read the first two bytes to determine if this is a * version 2 message */ if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && type == GNUTLS_HANDSHAKE && headers[0] > 127 && !(IS_DTLS(session))) { /* if msb set and expecting handshake message * it should be SSL 2 hello */ record->version[0] = 3; /* assume SSL 3.0 */ record->version[1] = 0; record->length = (((headers[0] & 0x7f) << 8)) | headers[1]; /* SSL 2.0 headers */ record->header_size = record->packet_size = 2; record->type = GNUTLS_HANDSHAKE; /* we accept only v2 client hello */ /* in order to assist the handshake protocol. * V2 compatibility is a mess. */ record->v2 = 1; record->epoch = 0; memset(&record->sequence, 0, sizeof(record->sequence)); _gnutls_record_log ("REC[%p]: SSL 2.0 %s packet received. Length: %d\n", session, _gnutls_packet2str(record->type), record->length); } else { /* dtls version 1.0 and TLS version 1.x */ record->v2 = 0; record->type = headers[0]; record->version[0] = headers[1]; record->version[1] = headers[2]; if (IS_DTLS(session)) { memcpy(record->sequence.i, &headers[3], 8); record->length = _gnutls_read_uint16(&headers[11]); record->epoch = _gnutls_read_uint16(record->sequence.i); } else { memset(&record->sequence, 0, sizeof(record->sequence)); record->length = _gnutls_read_uint16(&headers[3]); record->epoch = 0; } _gnutls_record_log ("REC[%p]: SSL %d.%d %s packet received. Epoch %d, length: %d\n", session, (int) record->version[0], (int) record->version[1], _gnutls_packet2str(record->type), (int) record->epoch, record->length); } record->packet_size += record->length; }
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_verify_sig_params (session, &peer_cert, &vparams, &signature); _gnutls_gcert_deinit (&peer_cert); if (ret < 0) { gnutls_assert (); return ret; } 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; }
/* just read the username from the client key exchange. */ static int _gnutls_proc_psk_client_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { ssize_t data_size = _data_size; int ret; gnutls_datum_t username, psk_key; gnutls_psk_server_credentials_t cred; psk_auth_info_t info; cred = (gnutls_psk_server_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_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; ret = _gnutls_psk_pwd_find_entry(session, info->username, &psk_key); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_set_psk_session_key(session, &psk_key, NULL); if (ret < 0) { gnutls_assert(); goto error; } ret = 0; error: _gnutls_free_key_datum(&psk_key); return ret; }