TPM_RESULT TPM_ChangeAuth(TPM_KEY_HANDLE parentHandle, TPM_PROTOCOL_ID protocolID, TPM_ENCAUTH *newAuth, TPM_ENTITY_TYPE entityType, UINT32 encDataSize, BYTE *encData, TPM_AUTH *auth1, TPM_AUTH *auth2, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *parent; TPM_SESSION_DATA *session; TPM_SECRET plainAuth; info("TPM_ChangeAuth()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify entity authorization */ auth2->continueAuthSession = FALSE; session = tpm_get_auth(auth2->authHandle); if (session->type != TPM_ST_OIAP) return TPM_BAD_MODE; /* verify parent authorization */ res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; auth1->continueAuthSession = FALSE; session = tpm_get_auth(auth1->authHandle); if (session->type != TPM_ST_OSAP) return TPM_BAD_MODE; /* decrypt auth */ tpm_decrypt_auth_secret(*newAuth, session->sharedSecret, &session->lastNonceEven, plainAuth); /* decrypt the entity, replace authData, and encrypt it again */ if (entityType == TPM_ET_DATA) { TPM_SEALED_DATA seal; BYTE *seal_buf; /* decrypt entity */ if (decrypt_sealed_data(parent, encData, encDataSize, &seal, &seal_buf)) return TPM_DECRYPT_ERROR; /* verify auth2 */ res = tpm_verify_auth(auth2, seal.authData, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res; /* change authData and use it also for auth2 */ memcpy(seal.authData, plainAuth, sizeof(TPM_SECRET)); /* encrypt entity */ *outDataSize = parent->key.size >> 3; *outData = tpm_malloc(*outDataSize); if (encrypt_sealed_data(parent, &seal, *outData, outDataSize)) { tpm_free(encData); tpm_free(seal_buf); return TPM_ENCRYPT_ERROR; } tpm_free(seal_buf); } else if (entityType == TPM_ET_KEY) {
static int handle_emuldev_command(int devfd) { ssize_t in_len; uint32_t out_len; uint8_t in[TPM_CMD_BUF_SIZE], *out; int res; debug("waiting for commands..."); in_len = read(devfd, in, sizeof(in)); debug("received %d bytes", in_len); if (in_len <= 0) return errno == -EAGAIN ? 0 : in_len; out = NULL; res = tpm_handle_command(in, in_len, &out, &out_len); if (res < 0) { error("tpm_handle_command() failed"); if (ioctl(devfd, 0, 0) < 0) return -1; } else { debug("sending %d bytes", out_len); res = write(devfd, out, out_len); if (res < 0) { error("write(%d) failed: %s", out_len, strerror(errno)); if (errno != ECANCELED) return -1; } } tpm_free(out); return 0; }
static TPM_RESULT execute_MTM_InstallRIM(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 rimCertSize; TPM_RIM_CERTIFICATE rimCertIn; TPM_RIM_CERTIFICATE rimCertOut; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &rimCertSize) || tpm_unmarshal_TPM_RIM_CERTIFICATE(&ptr, &len, &rimCertIn) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = MTM_InstallRIM(&rimCertIn, &req->auth1, &rimCertOut); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + sizeof_TPM_RIM_CERTIFICATE(rimCertOut); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, sizeof_TPM_RIM_CERTIFICATE(rimCertOut)) || tpm_marshal_TPM_RIM_CERTIFICATE(&ptr, &len, &rimCertOut)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_RIM_CERTIFICATE(rimCertOut); return res; }
static TPM_RESULT execute_MTM_LoadVerificationKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_VERIFICATION_KEY_HANDLE parentKey; UINT32 verificationKeySize; TPM_VERIFICATION_KEY verificationKey; TPM_VERIFICATION_KEY_HANDLE verificationKeyHandle; BYTE loadMethod; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_VERIFICATION_KEY_HANDLE(&ptr, &len, &parentKey) || tpm_unmarshal_UINT32(&ptr, &len, &verificationKeySize) || tpm_unmarshal_TPM_VERIFICATION_KEY(&ptr, &len, &verificationKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = MTM_LoadVerificationKey(parentKey, &verificationKey, &req->auth1, &verificationKeyHandle, &loadMethod); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + 1; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_VERIFICATION_KEY_HANDLE(&ptr, &len, verificationKeyHandle) || tpm_marshal_BYTE(&ptr, &len, loadMethod)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; }
static int _tpm_read_from_storage(uint8_t **data, size_t *data_length) { int fh; ssize_t res; size_t total_length; #if defined(_WIN32) || defined(_WIN64) fh = open(tpm_storage_file, O_RDONLY | O_BINARY); #else fh = open(tpm_storage_file, O_RDONLY); #endif if (fh < 0) return -1; total_length = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); *data = tpm_malloc(total_length); if (*data == NULL) { close(fh); return -1; } *data_length = 0; while (total_length > 0) { res = read(fh, &(*data)[*data_length], total_length); if (res < 0) { close(fh); tpm_free(*data); return -1; } if (res == 0) break; *data_length += res; total_length -= res; } close(fh); return 0; }
static TPM_RESULT execute_MTM_VerifyRIMCertAndExtend(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 rimCertSize; TPM_RIM_CERTIFICATE rimCert; TPM_VERIFICATION_KEY_HANDLE rimKey; TPM_PCRVALUE outDigest; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &rimCertSize) || tpm_unmarshal_TPM_RIM_CERTIFICATE(&ptr, &len, &rimCert) || tpm_unmarshal_TPM_VERIFICATION_KEY_HANDLE(&ptr, &len, &rimKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = MTM_VerifyRIMCertAndExtend(&rimCert, rimKey, &outDigest); /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PCRVALUE(&ptr, &len, &outDigest)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; }
inline TPM_RESULT return_BOOL(UINT32 *respSize, BYTE **resp, BOOL value) { UINT32 len = *respSize = 1; BYTE *ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_BOOL(&ptr, &len, value)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; }
/* manufacturer specific */ static TPM_RESULT cap_mfr(UINT32 *respSize, BYTE **resp) { UINT32 len = *respSize = 4; BYTE *ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_TPM_VERSION(&ptr, &len, &tpmData.permanent.data.version)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; }
static int compute_context_digest(TPM_CONTEXT_BLOB *contextBlob, TPM_DIGEST *digest) { BYTE *buf, *ptr; UINT32 len; tpm_hmac_ctx_t hmac_ctx; len = sizeof_TPM_CONTEXT_BLOB((*contextBlob)); buf = ptr = tpm_malloc(len); if (buf == NULL) return -1; if (tpm_marshal_TPM_CONTEXT_BLOB(&ptr, &len, contextBlob)) { tpm_free(buf); return -1; } memset(&buf[30], 0, 20); tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(tpmData.permanent.data.tpmProof.nonce)); tpm_hmac_update(&hmac_ctx, buf, sizeof_TPM_CONTEXT_BLOB((*contextBlob))); tpm_hmac_final(&hmac_ctx, digest->digest); tpm_free(buf); return 0; }
TPM_RESULT cap_flag(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { UINT32 type, len; BYTE *ptr; if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &type)) return TPM_BAD_MODE; switch (type) { case TPM_CAP_FLAG_PERMANENT: debug("[TPM_CAP_FLAG_PERMANENT"); *respSize = len = sizeof_TPM_PERMANENT_FLAGS(tpmData.permanent.flags); *resp = ptr = tpm_malloc(len); if (tpm_marshal_TPM_PERMANENT_FLAGS(&ptr, &len, &tpmData.permanent.flags)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; case TPM_CAP_FLAG_VOLATILE: debug("[TPM_CAP_FLAG_VOLATILE]"); *respSize = len = sizeof_TPM_STCLEAR_FLAGS(tpmData.stclear.flags); *resp = ptr = tpm_malloc(len); if (tpm_marshal_TPM_STCLEAR_FLAGS(&ptr, &len, &tpmData.stclear.flags)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; /* removed since v1.2 rev 94 case TPM_CAP_FLAG_STANY: debug("[TPM_CAP_FLAG_STANY]"); *respSize = len = sizeof_TPM_STANY_FLAGS(tpmData.stany.flags); *resp = ptr = tpm_malloc(len); if (tpm_marshal_TPM_STANY_FLAGS(&ptr, &len, &tpmData.stany.flags)) { tpm_free(*resp); return TPM_FAIL; } */ return TPM_SUCCESS; default: return TPM_BAD_MODE; } }
/* changed since rev 94: returned version MUST BE 1.1.0.0 */ static TPM_RESULT cap_version(UINT32 *respSize, BYTE **resp) { UINT32 len = *respSize = 4; BYTE *ptr = *resp = tpm_malloc(*respSize); TPM_STRUCT_VER version; version.major = version.minor = 1; version.revMajor = version.revMinor = 0; if (ptr == NULL || tpm_marshal_TPM_STRUCT_VER(&ptr, &len, &version)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; }
static int tpm_compute_migration_digest(TPM_PUBKEY *migrationKey, TPM_MIGRATE_SCHEME migrationScheme, TPM_NONCE *tpmProof, TPM_DIGEST *digest) { tpm_sha1_ctx_t sha1; UINT32 len = sizeof_TPM_PUBKEY((*migrationKey)); BYTE *buf, *ptr, buf2[2]; buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, migrationKey)) { tpm_free(buf); return -1; } /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof_TPM_PUBKEY((*migrationKey))); ptr = buf2; len = 2; tpm_marshal_UINT16(&ptr, &len, migrationScheme); tpm_sha1_update(&sha1, buf2, 2); tpm_sha1_update(&sha1, tpmProof->nonce, sizeof(TPM_NONCE)); tpm_sha1_final(&sha1, digest->digest); tpm_free(buf); return 0; }
static int decrypt_transport_auth(TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, TPM_TRANSPORT_AUTH *trans_auth) { BYTE *buf; size_t buf_size; int scheme; switch (key->encScheme) { case TPM_ES_RSAESOAEP_SHA1_MGF1: scheme = RSA_ES_OAEP_SHA1; break; case TPM_ES_RSAESPKCSv15: scheme = RSA_ES_PKCSV15; break; default: return -1; } buf = tpm_malloc(key->key.size); if (buf == NULL || tpm_rsa_decrypt(&key->key, scheme, enc, enc_size, buf, &buf_size) || buf_size != sizeof_TPM_TRANSPORT_AUTH(x) || (((UINT16)buf[0] << 8) | buf[1]) != TPM_TAG_TRANSPORT_AUTH) { tpm_free(buf); return -1; } trans_auth->tag = TPM_TAG_TRANSPORT_AUTH; memcpy(trans_auth->authData, &buf[2], sizeof(TPM_AUTHDATA)); tpm_free(buf); return 0; }
static int decrypt_context(BYTE *iv, UINT32 iv_size, BYTE *enc, UINT32 enc_size, TPM_CONTEXT_SENSITIVE *context, BYTE **buf) { UINT32 len; BYTE *ptr; tpm_rc4_ctx_t rc4_ctx; BYTE key[TPM_SYM_KEY_SIZE + iv_size]; len = enc_size; *buf = ptr = tpm_malloc(len); if (*buf == NULL) return -1; /* decrypt context */ memcpy(key, tpmData.permanent.data.contextKey, TPM_SYM_KEY_SIZE); memcpy(&key[TPM_SYM_KEY_SIZE], iv, iv_size); tpm_rc4_init(&rc4_ctx, key, sizeof(key)); tpm_rc4_crypt(&rc4_ctx, enc, *buf, enc_size); /* unmarshal context */ if (tpm_unmarshal_TPM_CONTEXT_SENSITIVE(&ptr, &len, context)) { tpm_free(*buf); return -1; } return 0; }
static int encrypt_context(BYTE *iv, UINT32 iv_size, TPM_CONTEXT_SENSITIVE *context, BYTE **enc, UINT32 *enc_size) { UINT32 len; BYTE *ptr; tpm_rc4_ctx_t rc4_ctx; BYTE key[TPM_SYM_KEY_SIZE + iv_size]; /* marshal context */ *enc_size = len = sizeof_TPM_CONTEXT_SENSITIVE((*context)); *enc = ptr = tpm_malloc(len); if (*enc == NULL) return -1; if (tpm_marshal_TPM_CONTEXT_SENSITIVE(&ptr, &len, context)) { tpm_free(*enc); return -1; } /* encrypt context */ memcpy(key, tpmData.permanent.data.contextKey, TPM_SYM_KEY_SIZE); memcpy(&key[TPM_SYM_KEY_SIZE], iv, iv_size); tpm_rc4_init(&rc4_ctx, key, sizeof(key)); tpm_rc4_crypt(&rc4_ctx, *enc, *enc, *enc_size); return 0; }
/* TODO: added since rev 94 */ TPM_RESULT cap_version_val(UINT32 *respSize, BYTE **resp) { UINT32 len; BYTE *ptr; TPM_CAP_VERSION_INFO version; version.tag = TPM_TAG_CAP_VERSION_INFO; version.version = tpmData.permanent.data.version; version.specLevel = 2; version.errataRev = 94; memset(version.tpmVendorID, 0, sizeof(version.tpmVendorID)); version.vendorSpecificSize = 0; version.vendorSpecific = NULL; len = *respSize = sizeof_TPM_CAP_VERSION_INFO(version); ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_TPM_CAP_VERSION_INFO(&ptr, &len, &version)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; }
TPM_RESULT TPM_ExecuteTransport(UINT32 inWrappedCmdSize, BYTE *inWrappedCmd, TPM_AUTH *auth1, UINT64 *currentTicks, TPM_MODIFIER_INDICATOR *locality, UINT32 *outWrappedCmdSize, BYTE **outWrappedCmd) { TPM_RESULT res; TPM_SESSION_DATA *session; TPM_REQUEST req; TPM_RESPONSE rsp; BYTE *ptr, buf[4 * 4 + 8 + 20]; UINT32 len, offset; tpm_sha1_ctx_t sha1; info("TPM_ExecuteTransport()"); /* get transport session */ session = tpm_get_transport(auth1->authHandle); if (session == NULL) return TPM_BAD_PARAMETER; /* unmarshal wrapped command */ len = inWrappedCmdSize; ptr = inWrappedCmd; if (tpm_unmarshal_TPM_REQUEST(&ptr, &len, &req)) return TPM_FAIL; /* decrypt wrapped command if needed */ ptr = tpm_malloc(req.paramSize); if (ptr == NULL) return TPM_FAIL; memcpy(ptr, req.param, req.paramSize); if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) { if (req.ordinal == TPM_ORD_OIAP || req.ordinal == TPM_ORD_OSAP) { offset = req.paramSize; } else if (req.ordinal == TPM_ORD_DSAP) { offset = 30; } else { offset = tpm_get_in_param_offset(req.ordinal); } debug("decrypting %d bytes, starting at pos %d", req.paramSize - offset, offset); decrypt_wrapped_command(ptr + offset, req.paramSize - offset, auth1, session); } req.param = ptr; /* verify authorization */ tpm_compute_in_param_digest(&req); tpm_sha1_init(&sha1); tpm_sha1_update_be32(&sha1, TPM_ORD_ExecuteTransport); tpm_sha1_update_be32(&sha1, inWrappedCmdSize); tpm_sha1_update(&sha1, req.auth1.digest, sizeof(req.auth1.digest)); tpm_sha1_final(&sha1, auth1->digest); res = tpm_verify_auth(auth1, session->transInternal.authData, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) { tpm_free(req.param); return res; } /* nested transport sessions are not allowed */ if (req.ordinal == TPM_ORD_EstablishTransport || req.ordinal == TPM_ORD_ExecuteTransport || req.ordinal == TPM_ORD_ReleaseTransportSigned) { tpm_free(req.param); return TPM_NO_WRAP_TRANSPORT; } /* log input parameters */ if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_LOG) { TPM_DIGEST keyDigest; compute_key_digest(&req, &keyDigest); transport_log_in(req.auth1.digest, keyDigest.digest, &session->transInternal.transDigest); } /* execute and audit command*/ tpm_audit_request(req.ordinal, &req); tpm_execute_command(&req, &rsp); tpm_audit_response(req.ordinal, &rsp); tpm_free(req.param); /* get locality and ticks */ *locality = tpmData.stany.flags.localityModifier; *currentTicks = tpmData.stany.data.currentTicks.currentTicks; /* if required, compute digest of internal output parameters */ debug("result = %d", rsp.result); if (rsp.result == TPM_SUCCESS) { if (rsp.tag == TPM_TAG_RSP_COMMAND) { rsp.auth1 = &req.auth1; tpm_compute_out_param_digest(req.ordinal, &rsp); } /* encrypt parameters */ if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) { if (req.ordinal == TPM_ORD_OIAP || req.ordinal == TPM_ORD_OSAP) { offset = rsp.paramSize; } else if (req.ordinal == TPM_ORD_DSAP) { offset = rsp.paramSize; } else { offset = tpm_get_out_param_offset(req.ordinal); } debug("encrypting %d bytes, starting at pos %d", rsp.paramSize - offset, offset); encrypt_wrapped_command(rsp.param + offset, rsp.paramSize - offset, auth1, session); } } else { rsp.auth1 = &req.auth1; memset(rsp.auth1->digest, 0, sizeof(*rsp.auth1->digest)); } /* marshal response */ *outWrappedCmdSize = len = rsp.size; *outWrappedCmd = ptr = tpm_malloc(len); if (ptr == NULL) { tpm_free(rsp.param); return TPM_FAIL; } tpm_marshal_TPM_RESPONSE(&ptr, &len, &rsp); debug("marshalling done."); /* log output parameters */ if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_LOG) { transport_log_out(rsp.auth1->digest, &session->transInternal.transDigest); } tpm_free(rsp.param); /* compute digest of output parameters */ ptr = buf; len = sizeof(buf); tpm_marshal_UINT32(&ptr, &len, TPM_SUCCESS); tpm_marshal_TPM_COMMAND_CODE(&ptr, &len, TPM_ORD_ExecuteTransport); tpm_marshal_UINT64(&ptr, &len, *currentTicks); tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, *locality); tpm_marshal_UINT32(&ptr, &len, *outWrappedCmdSize); memcpy(ptr, rsp.auth1->digest, sizeof(rsp.auth1->digest)); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof(buf)); tpm_sha1_final(&sha1, auth1->digest); return TPM_SUCCESS; }
int tpm_store_permanent_data(void) { uint8_t *buf, *ptr; size_t buf_length; uint32_t len; /* marshal data */ buf_length = len = sizeof_TPM_VERSION(tpmData.permanent.data.version) #ifdef MTM_EMULATOR + sizeof_TPM_DATA(tpmData) + sizeof_MTM_DATA(mtmData); #else + sizeof_TPM_DATA(tpmData); #endif debug("size of permanent data: %d", buf_length); buf = ptr = tpm_malloc(buf_length); if (buf == NULL || tpm_marshal_TPM_VERSION(&ptr, &len, &tpmData.permanent.data.version) #ifdef MTM_EMULATOR || tpm_marshal_TPM_DATA(&ptr, &len, &tpmData) || tpm_marshal_MTM_DATA(&ptr, &len, &mtmData)) { #else || tpm_marshal_TPM_DATA(&ptr, &len, &tpmData)) { #endif tpm_free(buf); return -1; } if (len != 0) debug("warning: buffer was too large, %d bytes left", len); if (tpm_write_to_storage(buf, buf_length - len)) { tpm_free(buf); return -1; } tpm_free(buf); return 0; } int tpm_restore_permanent_data(void) { uint8_t *buf, *ptr; size_t buf_length; uint32_t len; TPM_VERSION ver; /* read data */ if (tpm_read_from_storage(&buf, &buf_length)) return -1; ptr = buf; len = buf_length; /* unmarshal data */ if (tpm_unmarshal_TPM_VERSION(&ptr, &len, &ver) || memcmp(&ver, &tpm_version, sizeof(TPM_VERSION)) || tpm_unmarshal_TPM_DATA(&ptr, &len, &tpmData) #ifdef MTM_EMULATOR || tpm_unmarshal_MTM_DATA(&ptr, &len, &mtmData) #endif || len > 0) { tpm_free(buf); return -1; } tpm_free(buf); tpmData.permanent.flags.dataRestored = TRUE; return 0; }
TPM_RESULT TPM_LoadContext(TPM_HANDLE entityHandle, BOOL keepHandle, UINT32 contextSize, TPM_CONTEXT_BLOB *contextBlob, TPM_HANDLE *handle) { TPM_CONTEXT_SENSITIVE context; BYTE *context_buf; TPM_SESSION_DATA *session; TPM_DAA_SESSION_DATA *sessionDAA; TPM_KEY_DATA *key; TPM_DIGEST digest; int i = 0; info("TPM_LoadContext()"); if (decrypt_context(contextBlob->additionalData, contextBlob->additionalSize, contextBlob->sensitiveData, contextBlob->sensitiveSize, &context, &context_buf)) return TPM_DECRYPT_ERROR; /* validate structure */ if (compute_context_digest(contextBlob, &digest) || memcmp(&digest, &contextBlob->integrityDigest, sizeof(TPM_DIGEST))) { tpm_free(context_buf); return TPM_BADCONTEXT; } if (contextBlob->resourceType == TPM_RT_KEY) { /* check contextNonce */ if (context.internalData.key.parentPCRStatus || (context.internalData.key.keyFlags & TPM_KEY_FLAG_VOLATILE)) { if (memcmp(&context.contextNonce, &tpmData.stclear.data.contextNonceKey, sizeof(TPM_NONCE)) != 0) { tpm_free(context_buf); return TPM_BADCONTEXT; } } /* check handle */ key = tpm_get_key_slot(entityHandle); if (key == NULL || !key->payload) { if (keepHandle) { tpm_free(context_buf); return TPM_BAD_HANDLE; } *handle = tpm_get_free_key(); if (*handle == TPM_INVALID_HANDLE) { tpm_free(context_buf); return TPM_RESOURCES; } key = &tpmData.permanent.data.keys[HANDLE_TO_INDEX(*handle)]; } else { *handle = entityHandle; } /* reload resource */ memcpy(key, &context.internalData.key, sizeof(TPM_KEY_DATA)); tpm_rsa_copy_key(&key->key, &context.internalData.key.key); } else if (contextBlob->resourceType == TPM_RT_DAA_TPM) { /* check contextNonce */ if (memcmp(&context.contextNonce, &tpmData.stany.data.contextNonceSession, sizeof(TPM_NONCE)) != 0) { tpm_free(context_buf); return TPM_BADCONTEXT; } /* check context list */ for (i = 0; i < TPM_MAX_SESSION_LIST; i++) if (tpmData.stany.data.contextList[i] == contextBlob->contextCount) break; if (i >= TPM_MAX_SESSION_LIST) { tpm_free(context_buf); return TPM_BADCONTEXT; } tpmData.stany.data.contextList[i] = 0; /* check handle */ info("entityHandle = %08x, keepHandle = %d", entityHandle, keepHandle); sessionDAA = tpm_get_daa_slot(entityHandle); if (sessionDAA == NULL) { if (keepHandle) { tpm_free(context_buf); return TPM_BAD_HANDLE; } *handle = tpm_get_free_daa_session(); if (*handle == TPM_INVALID_HANDLE) { tpm_free(context_buf); return TPM_RESOURCES; } sessionDAA = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(*handle)]; } else if (sessionDAA->type != TPM_ST_INVALID) { if (keepHandle) { tpm_free(context_buf); return TPM_BAD_HANDLE; } *handle = tpm_get_free_daa_session(); if (*handle == TPM_INVALID_HANDLE) { tpm_free(context_buf); return TPM_RESOURCES; } sessionDAA = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(*handle)]; } else { if (HANDLE_TO_RT(entityHandle) != TPM_RT_DAA_TPM) { if (keepHandle) { tpm_free(context_buf); return TPM_BAD_HANDLE; } *handle = tpm_get_free_daa_session(); if (*handle == TPM_INVALID_HANDLE) { tpm_free(context_buf); return TPM_RESOURCES; } sessionDAA = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(*handle)]; } else *handle = entityHandle; } /* reload resource */ tpmData.stany.data.currentDAA = *handle; info("stany.data.currentDAA := %.8x", *handle); memset(sessionDAA, 0, sizeof(TPM_DAA_SESSION_DATA)); memcpy(sessionDAA, &context.internalData.sessionDAA, context.internalSize); } else { /* check contextNonce */ if (memcmp(&context.contextNonce, &tpmData.stany.data.contextNonceSession, sizeof(TPM_NONCE)) != 0) { tpm_free(context_buf); return TPM_BADCONTEXT; } if (context.internalData.session.type == TPM_ST_OSAP && tpm_get_key(context.internalData.session.handle) == NULL) { tpm_free(context_buf); return TPM_RESOURCEMISSING; } /* check context list */ for (i = 0; i < TPM_MAX_SESSION_LIST; i++) if (tpmData.stany.data.contextList[i] == contextBlob->contextCount) break; if (i >= TPM_MAX_SESSION_LIST) { tpm_free(context_buf); return TPM_BADCONTEXT; } tpmData.stany.data.contextList[i] = 0; /* check handle */ session = tpm_get_session_slot(entityHandle); if (session == NULL || session->type != TPM_ST_INVALID) { if (keepHandle) { tpm_free(context_buf); return TPM_BAD_HANDLE; } *handle = tpm_get_free_session(context.internalData.session.type); if (*handle == TPM_INVALID_HANDLE) { tpm_free(context_buf); return TPM_RESOURCES; } session = &tpmData.stany.data.sessions[HANDLE_TO_INDEX(*handle)]; } else { *handle = entityHandle; } /* reload resource */ memcpy(session, &context.internalData.session, sizeof(TPM_SESSION_DATA)); } tpm_free(context_buf); return TPM_SUCCESS; }
TPM_RESULT TPM_SaveContext(TPM_HANDLE handle, TPM_RESOURCE_TYPE resourceType, const BYTE label[16], UINT32 *contextSize, TPM_CONTEXT_BLOB *contextBlob) { TPM_CONTEXT_SENSITIVE context; TPM_SESSION_DATA *session = NULL; TPM_DAA_SESSION_DATA *sessionDAA = NULL; TPM_KEY_DATA *key = NULL; int i = 0; info("TPM_SaveContext() resourceType = %08x", resourceType); /* setup context data */ context.tag = TPM_TAG_CONTEXT_SENSITIVE; context.resourceType = resourceType; if (resourceType == TPM_RT_AUTH || resourceType == TPM_RT_TRANS) { session = (resourceType == TPM_RT_AUTH) ? tpm_get_auth(handle) : tpm_get_transport(handle); if (session == NULL) return TPM_INVALID_RESOURCE; /* store session data */ memcpy(&context.internalData.session, session, sizeof(TPM_SESSION_DATA)); context.internalSize = sizeof_TPM_SESSION_DATA((*session)); /* set context nonce */ memcpy(&context.contextNonce, &tpmData.stany.data.contextNonceSession, sizeof(TPM_NONCE)); } else if (resourceType == TPM_RT_KEY) { key = tpm_get_key(handle); debug("resourceType = TPM_RT_KEY, handle = %08x, key = %p", handle, key); if (key == NULL) return TPM_INVALID_RESOURCE; if (key->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) return TPM_OWNER_CONTROL; /* store key data (shallow copy is ok) */ memcpy(&context.internalData.key, key, sizeof(TPM_KEY_DATA)); context.internalSize = sizeof_TPM_KEY_DATA((*key)); /* set context nonce */ memcpy(&context.contextNonce, &tpmData.stclear.data.contextNonceKey, sizeof(TPM_NONCE)); } else if (resourceType == TPM_RT_DAA_TPM) { sessionDAA = tpm_get_daa(handle); if (sessionDAA == NULL) return TPM_INVALID_RESOURCE; /* store sessionDAA data */ memcpy(&context.internalData.sessionDAA, sessionDAA, sizeof(TPM_DAA_SESSION_DATA)); context.internalSize = sizeof(TPM_DAA_SESSION_DATA); /* set context nonce */ memcpy(&context.contextNonce, &tpmData.stany.data.contextNonceSession, sizeof(TPM_NONCE)); } else { return TPM_INVALID_RESOURCE; } /* setup context blob */ contextBlob->tag = TPM_TAG_CONTEXTBLOB; contextBlob->resourceType = resourceType; contextBlob->handle = handle; memset(&contextBlob->integrityDigest, 0, sizeof(TPM_DIGEST)); memcpy(contextBlob->label, label, sizeof(contextBlob->label)); contextBlob->additionalSize = TPM_SYM_KEY_SIZE; contextBlob->additionalData = tpm_malloc(contextBlob->additionalSize); if (contextBlob->additionalData == NULL) return TPM_FAIL; tpm_get_random_bytes(contextBlob->additionalData, contextBlob->additionalSize); /* increment context counter */ if (resourceType == TPM_RT_KEY) { contextBlob->contextCount = 0; } else { if (tpmData.stany.data.contextCount >= 0xfffffffc) { tpm_free(contextBlob->additionalData); return TPM_TOOMANYCONTEXTS; } contextBlob->contextCount = ++tpmData.stany.data.contextCount; for (i = 0; i < TPM_MAX_SESSION_LIST; i++) { if (tpmData.stany.data.contextList[i] == 0) break; } if (i >= TPM_MAX_SESSION_LIST) { tpm_free(contextBlob->additionalData); return TPM_NOCONTEXTSPACE; } tpmData.stany.data.contextCount++; tpmData.stany.data.contextList[i] = tpmData.stany.data.contextCount; contextBlob->contextCount = tpmData.stany.data.contextCount; } debug("context counter = %d", tpmData.stany.data.contextCount); /* encrypt sensitive data */ if (encrypt_context(contextBlob->additionalData, contextBlob->additionalSize, &context, &contextBlob->sensitiveData, &contextBlob->sensitiveSize)) { tpm_free(contextBlob->additionalData); return TPM_ENCRYPT_ERROR; } /* compute context digest */ if (compute_context_digest(contextBlob, &contextBlob->integrityDigest)) { tpm_free(contextBlob->additionalData); return TPM_FAIL; } *contextSize = sizeof_TPM_CONTEXT_BLOB((*contextBlob)); if (resourceType != TPM_RT_KEY) { /* The TPM MUST invalidate all information regarding the resource * except for information needed for reloading. */ if (resourceType != TPM_RT_DAA_TPM) session->type = TPM_ST_INVALID; else { memset(sessionDAA, 0, sizeof(TPM_DAA_SESSION_DATA)); sessionDAA->type = TPM_ST_INVALID; tpmData.stany.data.currentDAA = 0; } } return TPM_SUCCESS; }
static TPM_RESULT cap_handle(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { UINT32 i, len, type; BYTE *ptr; /* maximum of { TPM_MAX_KEYS, TPM_MAX_SESSIONS } */ UINT32 list_size = (TPM_MAX_KEYS > TPM_MAX_SESSIONS) ? TPM_MAX_KEYS : TPM_MAX_SESSIONS; UINT32 handles[list_size]; TPM_KEY_HANDLE_LIST list = { 0, handles }; if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &type)) return TPM_BAD_MODE; switch (type) { case TPM_RT_KEY: debug("[TPM_RT_KEY]"); for (i = 0; i < TPM_MAX_KEYS; i++) if (tpmData.permanent.data.keys[i].valid) { list.loaded++; list.handle[i] = INDEX_TO_KEY_HANDLE(i); } break; case TPM_RT_AUTH: debug("[TPM_RT_AUTH]"); for (i = 0; i < TPM_MAX_SESSIONS; i++) if (tpmData.stany.data.sessions[i].type == TPM_ST_OIAP || tpmData.stany.data.sessions[i].type == TPM_ST_OSAP) { list.loaded++; list.handle[i] = INDEX_TO_AUTH_HANDLE(i); } break; case TPM_RT_TRANS: debug("[TPM_RT_TRANS]"); for (i = 0; i < TPM_MAX_SESSIONS; i++) if (tpmData.stany.data.sessions[i].type == TPM_ST_TRANSPORT) { list.loaded++; list.handle[i] = INDEX_TO_TRANS_HANDLE(i); } break; /* removed since v1.2 rev 94 case TPM_RT_DELEGATE: debug("[TPM_RT_DELEGATE]"); break; */ case TPM_RT_COUNTER: debug("[TPM_RT_COUNTER]"); for (i = 0; i < TPM_MAX_COUNTERS; i++) if (tpmData.permanent.data.counters[i].valid) { list.loaded++; list.handle[i] = INDEX_TO_COUNTER_HANDLE(i); } break; case TPM_RT_CONTEXT: /* TODO: implement TPM_CAP_HANDLE for TPM_RT_CONTEXT */ default: return TPM_BAD_MODE; } /* marshal handle list */ len = *respSize = 2 + list.loaded * 4; ptr = *resp = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY_HANDLE_LIST(&ptr, &len, &list)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; }
static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { UINT32 i, j, property; if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &property)) return TPM_BAD_MODE; switch (property) { case TPM_CAP_PROP_PCR: debug("[TPM_CAP_PROP_PCR]"); return return_UINT32(respSize, resp, TPM_NUM_PCR); case TPM_CAP_PROP_DIR: debug("[TPM_CAP_PROP_DIR]"); return return_UINT32(respSize, resp, 1); case TPM_CAP_PROP_MANUFACTURER: debug("[TPM_CAP_PROP_MANUFACTURER]"); return return_UINT32(respSize, resp, TPM_MANUFACTURER); case TPM_CAP_PROP_KEYS: debug("[TPM_CAP_PROP_KEYS]"); for (i = 0, j = TPM_MAX_KEYS; i < TPM_MAX_KEYS; i++) if (tpmData.permanent.data.keys[i].valid) j--; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_MIN_COUNTER: debug("[TPM_CAP_PROP_MIN_COUNTER]"); return return_UINT32(respSize, resp, 1); case TPM_CAP_PROP_AUTHSESS: debug("[TPM_CAP_PROP_AUTHSESS]"); for (i = 0, j = TPM_MAX_SESSIONS; i < TPM_MAX_SESSIONS; i++) if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) j--; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_TRANSESS: debug("[TPM_CAP_PROP_TRANSESS]"); for (i = 0, j = TPM_MAX_SESSIONS; i < TPM_MAX_SESSIONS; i++) if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) j--; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_COUNTERS: debug("[TPM_CAP_PROP_COUNTERS]"); for (i = 0, j = TPM_MAX_COUNTERS; i < TPM_MAX_COUNTERS; i++) if (tpmData.permanent.data.counters[i].valid) j--; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_MAX_AUTHSESS: debug("[TPM_CAP_PROP_MAX_AUTHSESS]"); return return_UINT32(respSize, resp, TPM_MAX_SESSIONS); case TPM_CAP_PROP_MAX_TRANSESS: debug("[TPM_CAP_PROP_MAX_TRANSESS]"); return return_UINT32(respSize, resp, TPM_MAX_SESSIONS); case TPM_CAP_PROP_MAX_COUNTERS: debug("[TPM_CAP_PROP_MAX_COUNTERS]"); return return_UINT32(respSize, resp, TPM_MAX_COUNTERS); case TPM_CAP_PROP_MAX_KEYS: debug("[TPM_CAP_PROP_MAX_KEYS]"); return return_UINT32(respSize, resp, TPM_MAX_KEYS); case TPM_CAP_PROP_OWNER: debug("[TPM_CAP_PROP_OWNER]"); return return_BOOL(respSize, resp, tpmData.permanent.flags.owned); case TPM_CAP_PROP_CONTEXT: debug("[TPM_CAP_PROP_CONTEXT]"); for (i = 0, j = 0; i < TPM_MAX_SESSION_LIST; i++) if (tpmData.stany.data.contextList[i] == 0) j++; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_MAX_CONTEXT: debug("[TPM_CAP_PROP_MAX_CONTEXT]"); return return_UINT32(respSize, resp, TPM_MAX_SESSION_LIST); case TPM_CAP_PROP_FAMILYROWS: debug("[TPM_CAP_PROP_FAMILYROWS]"); /* TODO: TPM_CAP_PROP_FAMILYROWS */ return TPM_FAIL; case TPM_CAP_PROP_TIS_TIMEOUT: debug("[TPM_CAP_PROP_TIS_TIMEOUT]"); /* TODO: TPM_CAP_PROP_TIS_TIMEOUT: Measure these values and determine correct ones */ UINT32 len = *respSize = 16; BYTE *ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, 200000) || tpm_marshal_UINT32(&ptr, &len, 200000) || tpm_marshal_UINT32(&ptr, &len, 200000) || tpm_marshal_UINT32(&ptr, &len, 200000)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; case TPM_CAP_PROP_STARTUP_EFFECT: debug("[TPM_CAP_PROP_STARTUP_EFFECT]"); /* TODO: TPM_CAP_PROP_STARTUP_EFFECT */ return TPM_FAIL; case TPM_CAP_PROP_DELEGATE_ROW: debug("[TPM_CAP_PROP_DELEGATE_ROW]"); /* TODO: TPM_CAP_PROP_DELEGATE_ROW */ return TPM_FAIL; case TPM_CAP_PROP_DAA_MAX: debug("[TPM_CAP_PROP_DAA_MAX]"); return return_UINT32(respSize, resp, TPM_MAX_SESSIONS_DAA); case TPM_CAP_PROP_SESSION_DAA: debug("[TPM_CAP_PROP_SESSION_DAA]"); for (i = 0, j = TPM_MAX_SESSIONS_DAA; i < TPM_MAX_SESSIONS_DAA; i++) if (tpmData.stany.data.sessionsDAA[i].type != TPM_ST_INVALID) j--; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_CONTEXT_DIST: debug("[TPM_CAP_PROP_CONTEXT_DIST]"); /* TODO: TPM_CAP_PROP_CONTEXT_DIST */ return TPM_FAIL; case TPM_CAP_PROP_DAA_INTERRUPT: debug("[TPM_CAP_PROP_DAA_INTERRUPT]"); /* A value of TRUE indicates that the TPM will accept ANY command * while executing a DAA Join or Sign. A value of FALSE indicates * that the TPM will invalidate the DAA Join or Sign upon the * receipt of any command other than the next join/sign in the * session or a TPM_SaveContext. */ return return_BOOL(respSize, resp, TRUE); case TPM_CAP_PROP_SESSIONS: debug("[TPM_CAP_PROP_SESSIONS]"); for (i = 0, j = TPM_MAX_SESSIONS; i < TPM_MAX_SESSIONS; i++) if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) j--; return return_UINT32(respSize, resp, j); case TPM_CAP_PROP_MAX_SESSIONS: debug("[TPM_CAP_PROP_MAX_SESSIONS]"); return return_UINT32(respSize, resp, TPM_MAX_SESSIONS); case TPM_CAP_PROP_CMK_RESTRICTION: debug("[TPM_CAP_PROP_CMK_RESTRICTION]"); /* TODO: TPM_CAP_PROP_CMK_RESTRICTION */ return TPM_FAIL; case TPM_CAP_PROP_DURATION: debug("[TPM_CAP_PROP_DURATION]"); /* TODO: TPM_CAP_PROP_DURATION: Measure these values and return accurate ones */ BYTE dur[]= {0x0,0x0,0x0,0xc,0x0,0x7,0xa1,0x20,0x0,0x1e,0x84,0x80,0x11,0xe1,0xa3,0x0}; *respSize = 16; *resp = tpm_malloc(*respSize); memcpy(*resp,dur,16); return TPM_FAIL; case TPM_CAP_PROP_ACTIVE_COUNTER: debug("[TPM_CAP_PROP_ACTIVE_COUNTER]"); /* TODO: TPM_CAP_PROP_ACTIVE_COUNTER */ return TPM_FAIL; case TPM_CAP_PROP_MAX_NV_AVAILABLE: debug("[TPM_CAP_PROP_MAX_NV_AVAILABLE]"); /* TODO: TPM_CAP_PROP_MAX_NV_AVAILABLE */ return TPM_FAIL; case TPM_CAP_PROP_INPUT_BUFFER: debug("[TPM_CAP_PROP_INPUT_BUFFER]"); /* TODO: TPM_CAP_PROP_INPUT_BUFFER */ return TPM_FAIL; default: return TPM_BAD_MODE; } }
TPM_RESULT TPM_CreateMigrationBlob(TPM_KEY_HANDLE parentHandle, TPM_MIGRATE_SCHEME migrationType, TPM_MIGRATIONKEYAUTH *migrationKeyAuth, UINT32 encDataSize, BYTE *encData, TPM_AUTH *auth1, TPM_AUTH *auth2, UINT32 *randomSize, BYTE **random, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *parent; TPM_SESSION_DATA *session; BYTE *key_buf; UINT32 key_buf_size; TPM_STORE_ASYMKEY store; TPM_PUBKEY_DATA key; info("TPM_CreateMigrationBlob()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify parent authorization */ res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; session = tpm_get_auth(auth2->authHandle); if (session == NULL || session->type != TPM_ST_OIAP) return TPM_AUTHFAIL; /* verify key properties */ if (parent->keyUsage != TPM_KEY_STORAGE) return TPM_INVALID_KEYUSAGE; /* decrypt private key */ if (tpm_decrypt_private_key(parent, encData, encDataSize, &store, &key_buf, &key_buf_size) != 0) { return TPM_DECRYPT_ERROR; } if (store.payload != TPM_PT_ASYM) { tpm_free(key_buf); return TPM_DECRYPT_ERROR; } debug("key size: %d / %d", store.privKey.keyLength, key_buf_size); /* verify migration authorization */ res = tpm_verify_auth(auth2, store.migrationAuth, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) { tpm_free(key_buf); return TPM_MIGRATEFAIL; } if (tpm_verify_migration_digest(migrationKeyAuth, &tpmData.permanent.data.tpmProof)) { debug("tpm_verify_migration_digest() failed"); tpm_free(key_buf); return TPM_MIGRATEFAIL; } debug("migration authorization is valid."); /* set public key */ if (tpm_setup_pubkey_data(&migrationKeyAuth->migrationKey, &key) != 0) { debug("tpm_setup_pubkey() failed"); tpm_free(key_buf); return TPM_FAIL; } /* perform migration */ if (migrationType == TPM_MS_REWRAP) { /* re-encrypt raw key data */ debug("migrationType = TPM_MS_REWRAP"); *random = NULL; *randomSize = 0; *outDataSize = key.key.size >> 3; *outData = tpm_malloc(*outDataSize); if (*outData == NULL) { free_TPM_PUBKEY_DATA(key); tpm_free(*outData); tpm_free(key_buf); return TPM_FAIL; } if (tpm_encrypt_public(&key, key_buf, key_buf_size, *outData, outDataSize) != 0) { free_TPM_PUBKEY_DATA(key); tpm_free(*outData); tpm_free(key_buf); return TPM_ENCRYPT_ERROR; } } else if (migrationType == TPM_MS_MIGRATE) {
static void main_loop(void) { int sock = -1, devfd = -1, fh, res, npoll; int32_t in_len; uint32_t out_len; uint8_t in[TPM_CMD_BUF_SIZE], *out; struct sockaddr_un addr; socklen_t addr_len; struct pollfd poll_table[2]; info("staring main loop"); /* open UNIX socket */ if (opt_socket_name) { sock = init_socket(opt_socket_name); if (sock < 0) exit(EXIT_FAILURE); } if (opt_dev_name) { devfd = init_device(opt_dev_name); if (devfd < 0) exit(EXIT_FAILURE); } /* init tpm emulator */ debug("initializing TPM emulator"); if (tpm_emulator_init(tpm_startup, tpm_config) != 0) { error("tpm_emulator_init() failed"); close(sock); unlink(opt_socket_name); exit(EXIT_FAILURE); } /* start command processing */ while (!stopflag) { /* wait for incomming connections */ debug("waiting for connections..."); npoll = 0; if (sock != -1) { poll_table[npoll].fd = sock; poll_table[npoll].events = POLLIN; poll_table[npoll++].revents = 0; } if (devfd != -1) { poll_table[npoll].fd = devfd; poll_table[npoll].events = POLLIN | POLLERR; poll_table[npoll++].revents = 0; } res = poll(poll_table, npoll, -1); if (res < 0) { error("poll(sock,dev) failed: %s", strerror(errno)); break; } if (devfd != -1 && poll_table[npoll - 1].revents) { /* if POLLERR was set, let read() handle it */ if (handle_emuldev_command(devfd) < 0) break; } if (sock == -1 || !poll_table[0].revents) continue; /* Beyond this point, npoll will always be 1 if the emulator device is * not open and 2 if it is, so we can just fill in the second slot of * the poll table unconditionally and rely on passing npoll to poll(). */ addr_len = sizeof(addr); fh = accept(sock, (struct sockaddr*)&addr, &addr_len); if (fh < 0) { error("accept() failed: %s", strerror(errno)); continue; } /* receive and handle commands */ in_len = 0; do { debug("waiting for commands..."); poll_table[0].fd = fh; poll_table[0].events = POLLIN; poll_table[0].revents = 0; poll_table[1].fd = devfd; poll_table[1].events = POLLIN | POLLERR; poll_table[1].revents = 0; res = poll(poll_table, npoll, TPM_COMMAND_TIMEOUT); if (res < 0) { error("poll(fh) failed: %s", strerror(errno)); close(fh); break; } else if (res == 0) { #ifdef TPMD_DISCONNECT_IDLE_CLIENTS info("connection closed due to inactivity"); close(fh); break; #else continue; #endif } if (poll_table[1].revents) { /* if POLLERR was set, let read() handle it */ if (handle_emuldev_command(devfd) < 0) break; } if (!poll_table[0].revents) continue; in_len = read(fh, in, sizeof(in)); if (in_len > 0) { debug("received %d bytes", in_len); out = NULL; res = tpm_handle_command(in, in_len, &out, &out_len); if (res < 0) { error("tpm_handle_command() failed"); } else { debug("sending %d bytes", out_len); uint32_t len = 0; while (len < out_len) { res = write(fh, &out[len], out_len - len); if (res < 0) { error("write(%d) failed: %s", out_len - len, strerror(errno)); break; } len += res; } tpm_free(out); } } } while (in_len > 0); close(fh); } /* shutdown tpm emulator */ tpm_emulator_shutdown(); /* close socket */ close(sock); unlink(opt_socket_name); info("main loop stopped"); }