/** * gnutls_session_get_data2: * @session: is a #gnutls_session_t type. * @data: is a pointer to a datum that will hold the session. * * Returns all session parameters needed to be stored to support resumption. * The client should call this, and store the returned session data. A session * may be resumed later by calling gnutls_session_set_data(). * * The returned @data are allocated and must be released using gnutls_free(). * * This function will fail if called prior to handshake completion. In * case of false start TLS, the handshake completes only after data have * been successfully received from the peer. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_session_get_data2(gnutls_session_t session, gnutls_datum_t *data) { int ret; if (data == NULL) { return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } if (gnutls_session_is_resumed(session) && session->internals.resumption_data.data) { ret = _gnutls_set_datum(data, session->internals.resumption_data.data, session->internals.resumption_data.size); if (ret < 0) return gnutls_assert_val(ret); return 0; } if (session->internals.resumable == RESUME_FALSE) return GNUTLS_E_INVALID_SESSION; ret = _gnutls_session_pack(session, data); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
int _gnutls_server_register_current_session(gnutls_session_t session) { gnutls_datum_t key; gnutls_datum_t content; int ret = 0; key.data = session->security_parameters.session_id; key.size = session->security_parameters.session_id_size; if (session->internals.resumable == RESUME_FALSE) { gnutls_assert(); return GNUTLS_E_INVALID_SESSION; } if (session->security_parameters.session_id == NULL || session->security_parameters.session_id_size == 0) { gnutls_assert(); return GNUTLS_E_INVALID_SESSION; } ret = _gnutls_session_pack(session, &content); if (ret < 0) { gnutls_assert(); return ret; } ret = store_session(session, key, content); _gnutls_free_datum(&content); return ret; }
static int pack_ticket(gnutls_session_t session, tls13_ticket_st *ticket, gnutls_datum_t *packed) { uint8_t *p; gnutls_datum_t state; int ret; ret = _gnutls_session_pack(session, &state); if (ret < 0) return gnutls_assert_val(ret); packed->size = 2 + 4 + 4 + 1 + ticket->prf->output_size + 1 + ticket->nonce_size + 2 + state.size + 12; packed->data = gnutls_malloc(packed->size); if (!packed->data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } p = packed->data; _gnutls_write_uint16(ticket->prf->id, p); p += 2; _gnutls_write_uint32(ticket->age_add, p); p += 4; _gnutls_write_uint32(ticket->lifetime, p); p += 4; *p = ticket->prf->output_size; p += 1; memcpy(p, ticket->resumption_master_secret, ticket->prf->output_size); p += ticket->prf->output_size; *p = ticket->nonce_size; p += 1; memcpy(p, ticket->nonce, ticket->nonce_size); p += ticket->nonce_size; _gnutls_write_uint16(state.size, p); p += 2; memcpy(p, state.data, state.size); p += state.size; _gnutls_write_uint32((uint64_t) ticket->creation_time.tv_sec >> 32, p); p += 4; _gnutls_write_uint32(ticket->creation_time.tv_sec & 0xFFFFFFFF, p); p += 4; _gnutls_write_uint32(ticket->creation_time.tv_nsec, p); ret = 0; cleanup: gnutls_free(state.data); 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); }
static int encrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, struct ticket_st *ticket) { cipher_hd_st cipher_hd; gnutls_datum_t key, IV; gnutls_datum_t state = {NULL,0}, encrypted_state = {NULL,0}; uint8_t iv[IV_SIZE]; gnutls_datum_t mac_secret; uint32_t t; int ret; /* Pack security parameters. */ ret = _gnutls_session_pack(session, &state); if (ret < 0) { gnutls_assert(); return ret; } encrypted_state.size = ((state.size + BLOCK_SIZE - 1) / BLOCK_SIZE) * BLOCK_SIZE; encrypted_state.data = gnutls_calloc(1, encrypted_state.size); if (!encrypted_state.data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } memcpy(encrypted_state.data, state.data, state.size); /* Encrypt state */ key.data = (void *) &priv->key[KEY_POS]; key.size = CIPHER_KEY_SIZE; IV.data = iv; IV.size = IV_SIZE; t = gnutls_time(0); memcpy(iv, &t, 4); ret = gnutls_rnd(GNUTLS_RND_NONCE, iv+4, IV_SIZE-4); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(CIPHER), &key, &IV, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data, encrypted_state.size); if (ret < 0) { gnutls_assert(); goto cleanup2; } /* Fill the ticket structure to compute MAC. */ memcpy(ticket->key_name, &priv->key[NAME_POS], KEY_NAME_SIZE); memcpy(ticket->IV, IV.data, IV.size); ticket->encrypted_state_len = encrypted_state.size; ticket->encrypted_state = encrypted_state.data; mac_secret.data = &priv->key[MAC_SECRET_POS]; mac_secret.size = MAC_SECRET_SIZE; ret = digest_ticket(&mac_secret, ticket, ticket->mac); if (ret < 0) { gnutls_assert(); goto cleanup2; } encrypted_state.data = NULL; ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: _gnutls_free_datum(&state); _gnutls_free_datum(&encrypted_state); return ret; }