int _gnutls_encrypt_session_ticket(gnutls_session_t session, const gnutls_datum_t *state, gnutls_datum_t *ticket_data) { cipher_hd_st cipher_hd; gnutls_datum_t IV; gnutls_datum_t encrypted_state = {NULL,0}; uint8_t iv[TICKET_IV_SIZE]; gnutls_datum_t stek_cipher_key, stek_mac_key, stek_key_name; struct ticket_st ticket; int ret; encrypted_state.size = ((state->size + TICKET_BLOCK_SIZE - 1) / TICKET_BLOCK_SIZE) * TICKET_BLOCK_SIZE; ticket_data->size = TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2 + encrypted_state.size + TICKET_MAC_SIZE; ticket_data->data = gnutls_calloc(1, ticket_data->size); if (!ticket_data->data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } encrypted_state.data = ticket_data->data + TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2; memcpy(encrypted_state.data, state->data, state->size); /* Retrieve ticket encryption keys */ if (_gnutls_get_session_ticket_encryption_key(session, &stek_key_name, &stek_mac_key, &stek_cipher_key) < 0) { ret = GNUTLS_E_ENCRYPTION_FAILED; goto cleanup; } /* Encrypt state */ IV.data = iv; IV.size = TICKET_IV_SIZE; ret = gnutls_rnd(GNUTLS_RND_NONCE, iv, TICKET_IV_SIZE); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(TICKET_CIPHER), &stek_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, stek_key_name.data, stek_key_name.size); memcpy(ticket.IV, IV.data, IV.size); ticket.encrypted_state_len = encrypted_state.size; ticket.encrypted_state = encrypted_state.data; ret = digest_ticket(&stek_mac_key, &ticket, ticket.mac); if (ret < 0) { gnutls_assert(); goto cleanup2; } encrypted_state.data = NULL; pack_ticket(&ticket, ticket_data); ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: _gnutls_free_datum(&encrypted_state); return ret; }
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; }
int _gnutls_decrypt_session_ticket(gnutls_session_t session, const gnutls_datum_t *ticket_data, gnutls_datum_t *state) { cipher_hd_st cipher_hd; gnutls_datum_t IV; gnutls_datum_t stek_key_name, stek_cipher_key, stek_mac_key; uint8_t cmac[TICKET_MAC_SIZE]; struct ticket_st ticket; int ret; /* callers must have that checked */ assert(!(session->internals.flags & GNUTLS_NO_TICKETS)); /* Retrieve ticket decryption keys */ if (_gnutls_get_session_ticket_decryption_key(session, ticket_data, &stek_key_name, &stek_mac_key, &stek_cipher_key) < 0) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); ret = unpack_ticket(ticket_data, &ticket); if (ret < 0) return ret; /* If the key name of the ticket does not match the one that is currently active, issue a new ticket. */ if (memcmp (ticket.key_name, stek_key_name.data, stek_key_name.size)) { ret = GNUTLS_E_DECRYPTION_FAILED; goto cleanup; } /* Check the integrity of ticket */ ret = digest_ticket(&stek_mac_key, &ticket, cmac); if (ret < 0) { gnutls_assert(); goto cleanup; } if (memcmp(ticket.mac, cmac, TICKET_MAC_SIZE)) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto cleanup; } if (ticket.encrypted_state_len % TICKET_BLOCK_SIZE != 0) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto cleanup; } /* Decrypt encrypted_state */ IV.data = ticket.IV; IV.size = TICKET_IV_SIZE; ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(TICKET_CIPHER), &stek_cipher_key, &IV, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state, ticket.encrypted_state_len); if (ret < 0) { gnutls_assert(); goto cleanup2; } state->data = ticket.encrypted_state; state->size = ticket.encrypted_state_len; ticket.encrypted_state = NULL; ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: deinit_ticket(&ticket); return ret; }
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; }