| /* Software-based Trusted Platform Module (TPM) Emulator |
| * Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net> |
| * |
| * This module is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published |
| * by the Free Software Foundation; either version 2 of the License, |
| * or (at your option) any later version. |
| * |
| * This module is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * $Id: tpm_counter.c 364 2010-02-11 10:24:45Z mast $ |
| */ |
| |
| #include "tpm_emulator.h" |
| #include "tpm_commands.h" |
| #include "tpm_handles.h" |
| #include "tpm_data.h" |
| |
| /* |
| * Monotonic Counter ([TPM_Part3], Section 25) |
| */ |
| |
| static TPM_ACTUAL_COUNT get_max_counter_value(void) |
| { |
| UINT32 i; |
| TPM_ACTUAL_COUNT max = 0; |
| for (i = 0; i < TPM_MAX_COUNTERS; i++) { |
| if (tpmData.permanent.data.counters[i].valid |
| && tpmData.permanent.data.counters[i].counter > max) |
| max = tpmData.permanent.data.counters[i].counter; |
| } |
| return max; |
| } |
| |
| static TPM_COUNT_ID get_free_counter(void) |
| { |
| UINT32 i; |
| for (i = 0; i < TPM_MAX_COUNTERS; i++) { |
| if (!tpmData.permanent.data.counters[i].valid) { |
| tpmData.permanent.data.counters[i].valid = TRUE; |
| return INDEX_TO_COUNTER_HANDLE(i); |
| } |
| } |
| return TPM_INVALID_HANDLE; |
| } |
| |
| TPM_RESULT TPM_CreateCounter(TPM_ENCAUTH *authData, BYTE label[4], |
| TPM_AUTH *auth1, TPM_COUNT_ID *countID, |
| TPM_COUNTER_VALUE *counterValue) |
| { |
| TPM_RESULT res; |
| TPM_COUNTER_VALUE *counter; |
| TPM_SESSION_DATA *session; |
| info("TPM_CreateCounter()"); |
| /* get a free counter if any is left */ |
| *countID = get_free_counter(); |
| counter = tpm_get_counter(*countID); |
| if (counter == NULL) return TPM_SIZE; |
| /* verify authorization */ |
| res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); |
| if (res != TPM_SUCCESS) return res; |
| auth1->continueAuthSession = FALSE; |
| session = tpm_get_auth(auth1->authHandle); |
| if ((session->type != TPM_ST_OSAP) && (session->type != TPM_ST_DSAP)) |
| return TPM_AUTHFAIL; |
| /* decrypt authorization secret */ |
| tpm_decrypt_auth_secret(*authData, session->sharedSecret, |
| &session->lastNonceEven, counter->usageAuth); |
| /* setup counter */ |
| counter->tag = TPM_TAG_COUNTER_VALUE; |
| memcpy(counter->label, label, 4); |
| counter->counter = get_max_counter_value() + 1; |
| memcpy(counterValue, counter, sizeof(TPM_COUNTER_VALUE)); |
| return TPM_SUCCESS; |
| } |
| |
| TPM_RESULT TPM_IncrementCounter(TPM_COUNT_ID countID, TPM_AUTH *auth1, |
| TPM_COUNTER_VALUE *count) |
| { |
| TPM_RESULT res; |
| TPM_COUNTER_VALUE *counter; |
| info("TPM_IncrementCounter()"); |
| /* get counter */ |
| counter = tpm_get_counter(countID); |
| if (counter == NULL) return TPM_BAD_COUNTER; |
| /* verify authorization */ |
| res = tpm_verify_auth(auth1, counter->usageAuth, countID); |
| if (res != TPM_SUCCESS) return res; |
| /* verify counter selection and increment counter */ |
| if (tpm_get_counter(tpmData.stclear.data.countID) != NULL |
| && tpmData.stclear.data.countID != countID) return TPM_BAD_COUNTER; |
| tpmData.stclear.data.countID = countID; |
| counter->counter++; |
| return TPM_SUCCESS; |
| } |
| |
| TPM_RESULT TPM_ReadCounter(TPM_COUNT_ID countID, TPM_COUNTER_VALUE *count) |
| { |
| TPM_COUNTER_VALUE *counter; |
| info("TPM_ReadCounter()"); |
| /* get counter */ |
| counter = tpm_get_counter(countID); |
| if (counter == NULL) return TPM_BAD_COUNTER; |
| memcpy(count, counter, sizeof(TPM_COUNTER_VALUE)); |
| return TPM_SUCCESS; |
| } |
| |
| TPM_RESULT TPM_ReleaseCounter(TPM_COUNT_ID countID, TPM_AUTH *auth1) |
| { |
| TPM_RESULT res; |
| TPM_COUNTER_VALUE *counter; |
| info("TPM_ReleaseCounter()"); |
| /* get counter */ |
| counter = tpm_get_counter(countID); |
| if (counter == NULL) return TPM_BAD_COUNTER; |
| /* verify authorization */ |
| res = tpm_verify_auth(auth1, counter->usageAuth, countID); |
| if (res != TPM_SUCCESS) return res; |
| /* release counter */ |
| if (tpmData.stclear.data.countID == countID) |
| tpmData.stclear.data.countID = TPM_INVALID_HANDLE; |
| memset(counter, 0, sizeof(TPM_COUNTER_VALUE)); |
| return TPM_SUCCESS; |
| } |
| |
| TPM_RESULT TPM_ReleaseCounterOwner(TPM_COUNT_ID countID, TPM_AUTH *auth1) |
| { |
| TPM_RESULT res; |
| TPM_COUNTER_VALUE *counter; |
| info("TPM_ReleaseCounterOwner()"); |
| /* get counter */ |
| counter = tpm_get_counter(countID); |
| if (counter == NULL) return TPM_BAD_COUNTER; |
| /* verify authorization */ |
| res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); |
| if (res != TPM_SUCCESS) return res; |
| /* release counter */ |
| if (tpmData.stclear.data.countID == countID) |
| tpmData.stclear.data.countID = TPM_INVALID_HANDLE; |
| memset(counter, 0, sizeof(TPM_COUNTER_VALUE)); |
| return TPM_SUCCESS; |
| } |
| |