/* This is a temporary function to be used before the generate_* internal API is changed to use mbuffers. For now we don't avoid the extra alloc + memcpy. */ static inline int send_handshake (gnutls_session_t session, opaque * data, size_t size, gnutls_handshake_description_t type) { mbuffer_st *bufel; if (data == NULL && size == 0) return _gnutls_send_handshake (session, NULL, type); if (data == NULL && size > 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } bufel = _gnutls_handshake_alloc(session, size, size); if (bufel == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _mbuffer_set_udata (bufel, data, size); return _gnutls_send_handshake (session, bufel, type); }
int _gnutls_send_server_certificate_status(gnutls_session_t session, int again) { mbuffer_st *bufel = NULL; uint8_t *data; int data_size = 0; int ret; status_request_ext_st *priv = NULL; extension_priv_data_t epriv; if (again == 0) { ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_STATUS_REQUEST, &epriv); if (ret < 0) return 0; priv = epriv.ptr; if (!priv->response.size) return 0; data_size = priv->response.size + 4; bufel = _gnutls_handshake_alloc(session, data_size, data_size); if (!bufel) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); data = _mbuffer_get_udata_ptr(bufel); data[0] = 0x01; _gnutls_write_uint24(priv->response.size, &data[1]); memcpy(&data[4], priv->response.data, priv->response.size); _gnutls_free_datum(&priv->response); } return _gnutls_send_handshake(session, data_size ? bufel : NULL, GNUTLS_HANDSHAKE_CERTIFICATE_STATUS); }
int _gnutls13_send_key_update(gnutls_session_t session, unsigned again, unsigned flags /* GNUTLS_KU_* */) { int ret; mbuffer_st *bufel = NULL; uint8_t val; if (again == 0) { if (flags & GNUTLS_KU_PEER) { /* mark that we asked a key update to prevent an * infinite ping pong when receiving the reply */ session->internals.hsk_flags |= HSK_KEY_UPDATE_ASKED; val = 0x01; } else { val = 0x00; } _gnutls_handshake_log("HSK[%p]: sending key update (%u)\n", session, (unsigned)val); bufel = _gnutls_handshake_alloc(session, 1); if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _mbuffer_set_udata_size(bufel, 0); ret = _mbuffer_append_data(bufel, &val, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } } return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_KEY_UPDATE); cleanup: _mbuffer_xfree(&bufel); return ret; }
/* * Return zero if session tickets haven't been enabled. */ int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) { mbuffer_st *bufel = NULL; uint8_t *data = NULL, *p; int data_size = 0; int ret; gnutls_datum_t state = { NULL, 0 }; uint16_t epoch_saved = session->security_parameters.epoch_write; gnutls_datum_t ticket_data; if (again == 0) { if (session->internals.flags & GNUTLS_NO_TICKETS) return 0; if (!session->internals.session_ticket_renew) return 0; _gnutls_handshake_log ("HSK[%p]: sending session ticket\n", session); /* XXX: Temporarily set write algorithms to be used. _gnutls_write_connection_state_init() does this job, but it also triggers encryption, while NewSessionTicket should not be encrypted in the record layer. */ ret = _gnutls_epoch_set_keys(session, session->security_parameters. epoch_next, 0); if (ret < 0) { gnutls_assert(); return ret; } /* Under TLS1.2 with session tickets, the session ID is used for different * purposes than the TLS1.0 session ID. Ensure that there is an internally * set value which the server will see on the original and resumed sessions */ if (session->internals.resumed != RESUME_TRUE) { ret = _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. session_id_size); if (ret < 0) { gnutls_assert(); return ret; } } session->security_parameters.epoch_write = session->security_parameters.epoch_next; /* Pack security parameters. */ ret = _gnutls_session_pack(session, &state); if (ret < 0) { gnutls_assert(); return ret; } /* Generate an encrypted ticket */ ret = _gnutls_encrypt_session_ticket(session, &state, &ticket_data); session->security_parameters.epoch_write = epoch_saved; _gnutls_free_datum(&state); if (ret < 0) { gnutls_assert(); return ret; } bufel = _gnutls_handshake_alloc(session, 4 + 2 + ticket_data.size); if (!bufel) { gnutls_assert(); _gnutls_free_datum(&ticket_data); return GNUTLS_E_MEMORY_ERROR; } data = _mbuffer_get_udata_ptr(bufel); p = data; _gnutls_write_uint32(session->internals.expire_time, p); p += 4; _gnutls_write_uint16(ticket_data.size, p); p += 2; memcpy(p, ticket_data.data, ticket_data.size); p += ticket_data.size; _gnutls_free_datum(&ticket_data); data_size = p - data; session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT; } return _gnutls_send_handshake(session, data_size ? bufel : NULL, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET); }
int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) { mbuffer_st *bufel = NULL; uint8_t *data = NULL, *p; int data_size = 0; int ret; struct ticket_st ticket; uint16_t ticket_len; session_ticket_ext_st *priv = NULL; extension_priv_data_t epriv; uint16_t epoch_saved = session->security_parameters.epoch_write; if (again == 0) { ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv); if (ret < 0) return 0; priv = epriv; if (!priv->session_ticket_renew) return 0; /* XXX: Temporarily set write algorithms to be used. _gnutls_write_connection_state_init() does this job, but it also triggers encryption, while NewSessionTicket should not be encrypted in the record layer. */ ret = _gnutls_epoch_set_keys(session, session->security_parameters. epoch_next); if (ret < 0) { gnutls_assert(); return ret; } session->security_parameters.epoch_write = session->security_parameters.epoch_next; ret = encrypt_ticket(session, priv, &ticket); session->security_parameters.epoch_write = epoch_saved; if (ret < 0) { gnutls_assert(); return ret; } ticket_len = KEY_NAME_SIZE + IV_SIZE + 2 + ticket.encrypted_state_len + MAC_SIZE; bufel = _gnutls_handshake_alloc(session, 4 + 2 + ticket_len); if (!bufel) { gnutls_assert(); gnutls_free(ticket.encrypted_state); return GNUTLS_E_MEMORY_ERROR; } data = _mbuffer_get_udata_ptr(bufel); p = data; _gnutls_write_uint32(session->internals.expire_time, p); p += 4; _gnutls_write_uint16(ticket_len, p); p += 2; memcpy(p, ticket.key_name, KEY_NAME_SIZE); p += KEY_NAME_SIZE; memcpy(p, ticket.IV, IV_SIZE); p += IV_SIZE; _gnutls_write_uint16(ticket.encrypted_state_len, p); p += 2; memcpy(p, ticket.encrypted_state, ticket.encrypted_state_len); gnutls_free(ticket.encrypted_state); p += ticket.encrypted_state_len; memcpy(p, ticket.mac, MAC_SIZE); p += MAC_SIZE; data_size = p - data; session->internals.ticket_sent = 1; } return _gnutls_send_handshake(session, data_size ? bufel : NULL, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET); }