/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary source code may only be used and distributed under the Widevine Master License Agreement. */ #include "oemcrypto_session_table.h" #include "stdint.h" #include "string.h" #include "assert_interface.h" #include "logging_interface.h" #include "oemcrypto_key.h" static SessionTable session_table; static uint32_t open_session_count = 0; static bool session_table_initialized = false; OEMCryptoResult InitializeSessionTable(void) { ASSERT(MAX_NUMBER_OF_SESSIONS > 0, "MAX_NUMBER_OF_SESSIONS must be > 0"); ASSERT(MAX_NUMBER_OF_SESSIONS <= UINT32_MAX - 1, "MAX_NUMBER_OF_SESSIONS is too large"); if (session_table_initialized) { return OEMCrypto_ERROR_INIT_FAILED; } session_table.first_free_session = 0; for (uint32_t i = 0; i < MAX_NUMBER_OF_SESSIONS; i++) { session_table.next_free_session[i] = i + 1; session_table.is_free[i] = true; memset(&session_table.sessions[i], 0, sizeof(OEMCryptoSession)); } session_table_initialized = true; open_session_count = 0; return OEMCrypto_SUCCESS; } uint32_t MaxNumberOfSessions(void) { return MAX_NUMBER_OF_SESSIONS; } OEMCryptoResult NumberOfOpenSessions(uint32_t* num_open_sessions) { ASSERT(num_open_sessions != NULL, "num_open_sessions is NULL"); if (!session_table_initialized) { return OEMCrypto_ERROR_SYSTEM_INVALIDATED; } *num_open_sessions = open_session_count; return OEMCrypto_SUCCESS; } OEMCryptoResult GrabSession(uint32_t* index) { ASSERT(index != NULL, "index is NULL"); if (!session_table_initialized) { return OEMCrypto_ERROR_SYSTEM_INVALIDATED; } if (session_table.first_free_session == MAX_NUMBER_OF_SESSIONS) { return OEMCrypto_ERROR_TOO_MANY_SESSIONS; } *index = session_table.first_free_session; session_table.first_free_session = session_table.next_free_session[*index]; session_table.is_free[*index] = false; open_session_count++; return InitializeSession(&session_table.sessions[*index], *index); } OEMCryptoResult GetSession(uint32_t index, OEMCryptoSession** session) { ASSERT(session != NULL, "session is NULL"); if (!session_table_initialized) { return OEMCrypto_ERROR_SYSTEM_INVALIDATED; } if (index >= MAX_NUMBER_OF_SESSIONS || session_table.is_free[index]) { return OEMCrypto_ERROR_INVALID_SESSION; } *session = &session_table.sessions[index]; return OEMCrypto_SUCCESS; } OEMCryptoResult FreeSession(uint32_t index) { if (!session_table_initialized) { return OEMCrypto_ERROR_SYSTEM_INVALIDATED; } if (index >= MAX_NUMBER_OF_SESSIONS || session_table.is_free[index]) { return OEMCrypto_ERROR_INVALID_SESSION; } session_table.next_free_session[index] = session_table.first_free_session; session_table.is_free[index] = true; session_table.first_free_session = index; open_session_count--; return TerminateSession(&session_table.sessions[index]); } OEMCryptoResult TerminateSessionTable(void) { if (!session_table_initialized) { return OEMCrypto_ERROR_TERMINATE_FAILED; } OEMCryptoResult result = OEMCrypto_SUCCESS; for (int i = 0; i < MAX_NUMBER_OF_SESSIONS; i++) { if (!session_table.is_free[i]) { result = OEMCrypto_ERROR_TERMINATE_FAILED; /* Attempt to free the session. */ OEMCryptoResult free_result = FreeSession(i); if (free_result != OEMCrypto_SUCCESS) { LOGE("Could not free session %d with error: %d", i, free_result); } } } session_table_initialized = false; open_session_count = 0; return result; }