/** * gnutls_session_set_data: * @session: is a #gnutls_session_t type. * @session_data: is a pointer to space to hold the session. * @session_data_size: is the session's size * * Sets all session parameters, in order to resume a previously * established session. The session data given must be the one * returned by gnutls_session_get_data(). This function should be * called before gnutls_handshake(). * * Keep in mind that session resuming is advisory. The server may * choose not to resume the session, thus a full handshake will be * performed. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise * an error code is returned. **/ int gnutls_session_set_data(gnutls_session_t session, const void *session_data, size_t session_data_size) { int ret; gnutls_datum_t psession; psession.data = (uint8_t *) session_data; psession.size = session_data_size; if (session_data == NULL || session_data_size == 0) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_session_unpack(session, &psession); if (ret < 0) { gnutls_assert(); return ret; } session->internals.resumption_requested = 1; if (session->internals.resumption_data.data != NULL) gnutls_free(session->internals.resumption_data.data); _gnutls_set_datum(&session->internals.resumption_data, session_data, session_data_size); return 0; }
static int unpack_session(gnutls_session_t session, const gnutls_datum_t *state) { int ret; if (unlikely(!state)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ret = _gnutls_session_unpack(session, state); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_check_resumed_params(session); if (ret < 0) return gnutls_assert_val(ret); session->internals.resumed = RESUME_TRUE; return 0; }
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; }
static int decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, struct ticket_st *ticket) { cipher_hd_st cipher_hd; gnutls_datum_t key, IV, state, mac_secret; uint8_t cmac[MAC_SIZE]; time_t timestamp = gnutls_time(0); int ret; /* Check the integrity of ticket */ mac_secret.data = (void *) &priv->key[MAC_SECRET_POS]; mac_secret.size = MAC_SECRET_SIZE; ret = digest_ticket(&mac_secret, ticket, cmac); if (ret < 0) return gnutls_assert_val(ret); if (memcmp(ticket->mac, cmac, MAC_SIZE)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (ticket->encrypted_state_len % BLOCK_SIZE != 0) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); /* Decrypt encrypted_state */ key.data = (void *) &priv->key[KEY_POS]; key.size = CIPHER_KEY_SIZE; IV.data = ticket->IV; IV.size = IV_SIZE; ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(CIPHER), &key, &IV, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_cipher_decrypt(&cipher_hd, ticket->encrypted_state, ticket->encrypted_state_len); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Unpack security parameters. */ state.data = ticket->encrypted_state; state.size = ticket->encrypted_state_len; ret = _gnutls_session_unpack(session, &state); if (ret < 0) { gnutls_assert(); goto cleanup; } if (timestamp - session->internals.resumed_security_parameters.timestamp > session->internals.expire_time || session->internals.resumed_security_parameters.timestamp > timestamp) { gnutls_assert(); ret = GNUTLS_E_EXPIRED; goto cleanup; } ret = _gnutls_check_resumed_params(session); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.resumed = RESUME_TRUE; ret = 0; cleanup: _gnutls_cipher_deinit(&cipher_hd); return ret; }