Repository: PeterHuewe/tpm-emulator Branch: master Commit: 334a54e874d4 Files: 104 Total size: 1.2 MB Directory structure: gitextract_w5yjmm2s/ ├── .gitignore ├── .travis.yml ├── AUTHORS ├── CMakeLists.txt ├── ChangeLog ├── LICENSE ├── README ├── build.bat ├── build.sh ├── config.h.in ├── crypto/ │ ├── CMakeLists.txt │ ├── bn.h │ ├── bn_gmp.c │ ├── bn_openssl.c │ ├── hmac.c │ ├── hmac.h │ ├── rc4.c │ ├── rc4.h │ ├── rsa.c │ ├── rsa.h │ ├── sha1.c │ └── sha1.h ├── mtm/ │ ├── CMakeLists.txt │ ├── mtm_capability.c │ ├── mtm_cmd_handler.c │ ├── mtm_commands.h │ ├── mtm_counter.c │ ├── mtm_data.c │ ├── mtm_data.h │ ├── mtm_eviction.c │ ├── mtm_handles.c │ ├── mtm_handles.h │ ├── mtm_integrity.c │ ├── mtm_marshalling.c │ ├── mtm_marshalling.h │ ├── mtm_structures.h │ └── mtm_verification.c ├── tddl/ │ ├── CMakeLists.txt │ ├── tddl-tpm-emulator.h │ ├── tddl.c │ ├── tddl_unix.h │ ├── tddl_windows.h │ └── test_tddl.c ├── tpm/ │ ├── CMakeLists.txt │ ├── tpm_audit.c │ ├── tpm_authorization.c │ ├── tpm_capability.c │ ├── tpm_cmd_handler.c │ ├── tpm_commands.h │ ├── tpm_context.c │ ├── tpm_counter.c │ ├── tpm_credentials.c │ ├── tpm_crypto.c │ ├── tpm_daa.c │ ├── tpm_data.c │ ├── tpm_data.h │ ├── tpm_delegation.c │ ├── tpm_deprecated.c │ ├── tpm_emulator.h │ ├── tpm_emulator_extern.c │ ├── tpm_emulator_extern.h │ ├── tpm_error.c │ ├── tpm_eviction.c │ ├── tpm_handles.c │ ├── tpm_handles.h │ ├── tpm_identity.c │ ├── tpm_integrity.c │ ├── tpm_maintenance.c │ ├── tpm_management.c │ ├── tpm_marshalling.c │ ├── tpm_marshalling.h │ ├── tpm_migration.c │ ├── tpm_nv_storage.c │ ├── tpm_owner.c │ ├── tpm_startup.c │ ├── tpm_storage.c │ ├── tpm_structures.h │ ├── tpm_testing.c │ ├── tpm_ticks.c │ └── tpm_transport.c ├── tpmd/ │ ├── CMakeLists.txt │ ├── unix/ │ │ ├── CMakeLists.txt │ │ └── tpmd.c │ └── windows/ │ ├── CMakeLists.txt │ ├── control_tpmd.bat │ └── tpmd.c └── tpmd_dev/ ├── CMakeLists.txt ├── darwin/ │ ├── English.lproj/ │ │ └── InfoPlist.strings │ ├── Info.plist │ ├── Makefile │ ├── tpm_bridge.c │ └── tpm_bridge.xcodeproj/ │ ├── TemplateIcon.tiff │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata/ │ │ └── admin.xcuserdatad/ │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings │ └── xcuserdata/ │ └── admin.xcuserdatad/ │ └── xcschemes/ │ ├── tpm_bridge.xcscheme │ └── xcschememanagement.plist ├── linux/ │ ├── Makefile │ ├── tpmd_dev.c │ └── tpmd_dev.rules.in └── openbsd/ ├── Makefile ├── tpmd_dev.c └── tpmd_dev.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ build/ ================================================ FILE: .travis.yml ================================================ env: global: secure: "J29/ntLw9L6cZwmzz/cuYKs7lZ30zGcAW+3BRys56BcBNGy/h1i/ScKuVNTVeGngYfnpVsifDheZNOv7u+WI6cjOiA3mQaf+vtYy/VPp49GVIKhrt1H8RK0+ZalkOy3V3FAIecH3BxbwAeGhmDmEbSr/Prhy3ijIVF/67j/Qx+GUNkY6AFWO78NUvsrx88RIbGJ6lMVz6RDdtmzwNnIS1cXRkxmeK8tfr1brf2jQoqSzUswmfLAYy/n0RoZww7VzcL5O/9nATon6b36hG8XAU04AINqko19/ZxQWUuX2kHwGe3UTRcHvzJSB+z2I/vumvnfLSoQI9Q4DO/uvd62ap+V/4Rbi2tEvNb/kqHMpB9BswCCJTZkGqRcCvgMjzLbVpbewQmlH4n2zD35uReeIiZibileG5flkVIa3x3Fw/mo0nWa5YKCE49cQsETPRLBdfleyqtFIaEScVxgDIWvxxJq9mCybvIZ9VgsthoKtcspCUcNen8ptNwzuGd2TzHeL5rs1WLJGwSlnIzGlRrbNsDb+HHgDCSZr7AKTE9H+JFbg3gKu8NtoM/M+KPXDUn03Z0RFYildsMh1Q8C58ZeHTPbX/ZMZN8VWRQfKD7YANueOEji37jeSDpWY2Iyq0Q0d65M/slm1jrR+x+C98VBpB/Iw8o1R/qOqFlqL9MXX6mg=" language: c addons: apt: packages: - libgmp-dev - linux-kernel-headers - build-essential - kernel-package - libssl-dev before_install: - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- addons: coverity_scan: project: name: "PeterHuewe/tpm-emulator" description: "PeterHuewe/tpm-emulator" notification_email: peterhuewe@gmx.de build_command_prepend: mkdir -p build && cd build && cmake -DBUILD_DEV=OFF ../ build_command: make branch_pattern: master script: mkdir -p build && cd build && cmake -DBUILD_DEV=OFF ../ && make && cd .. ================================================ FILE: AUTHORS ================================================ Mario Strasser Heiko Stamer [DAA] ================================================ FILE: CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 475 2011-12-20 18:21:19Z mast $ project(TPM_Emulator C) cmake_minimum_required(VERSION 2.4) include(GNUInstallDirs) set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif() # enforce out of source build string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" IS_INSOURCE) if(IS_INSOURCE) message(FATAL_ERROR "${PROJECT_NAME} requires an out of source build.") endif() # set project and build version set(${PROJECT_NAME}_VERSION_MAJOR 0) set(${PROJECT_NAME}_VERSION_MINOR 7) string(REGEX REPLACE ".*Revision: ([0-9]+).*" "\\1" ${PROJECT_NAME}_VERSION_BUILD "$Revision: 475 $") # create project configuration if(WIN32) STRING(REGEX REPLACE "\\\\" "/" PROGRAMFILES "$ENV{PROGRAMFILES}/${PROJECT_NAME}") set(TPM_LOG_FILE "${PROGRAMFILES}/tpmd.log") set(TPM_STORAGE_NAME "${PROGRAMFILES}/tpm_emulator-1_2_${${PROJECT_NAME}_VERSION_MAJOR}_${${PROJECT_NAME}_VERSION_MINOR}") set(TPM_DEVICE_NAME "//./pipe/tpmd:0") elseif(APPLE) set(TPM_LOG_FILE "/private/var/log/tpmd.log") set(TPM_SOCKET_NAME "/private/var/run/tpm/tpmd_socket:0") set(TPM_STORAGE_NAME "/private/var/lib/tpm/tpm_emulator-1_2_${${PROJECT_NAME}_VERSION_MAJOR}_${${PROJECT_NAME}_VERSION_MINOR}") set(TPM_DEVICE_NAME "/dev/tpm") else() set(TPM_LOG_FILE "/var/log/tpmd.log") set(TPM_SOCKET_NAME "/var/run/tpm/tpmd_socket:0") set(TPM_STORAGE_NAME "/var/lib/tpm/tpm_emulator-1_2_${${PROJECT_NAME}_VERSION_MAJOR}_${${PROJECT_NAME}_VERSION_MINOR}") set(TPM_DEVICE_NAME "/dev/tpm") endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) add_definitions(-Wall -Wno-unused-parameter -Wpointer-arith -Wcast-align -Wwrite-strings) option(ENABLE_WERROR "Make warnings into errors") if(ENABLE_WERROR) add_definitions(-Werror) endif() if("${CMAKE_SYSTEM}" MATCHES "Linux") add_definitions(-Wextra) endif() if(USE_OPENSSL) add_definitions(-DUSE_OPENSSL) endif() include_directories("/opt/local/include") link_directories("/opt/local/lib") # configure CPack set(CPACK_PACKAGE_VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR}) set(CPACK_SOURCE_PACKAGE_FILE_NAME "tpm_emulator-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.4") set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES ".svn/" "/build/" "/.project" "/.cproject") set(CPACK_GENERATOR "ZIP") set(CPACK_SET_DESTDIR ON) include(CPack) # include root directories include_directories(${CMAKE_SOURCE_DIR}) include_directories(${CMAKE_BINARY_DIR}) # add internal libraries add_subdirectory(tpm) option(MTM_EMULATOR "MTM emulator") if(MTM_EMULATOR) add_subdirectory(mtm) endif() add_subdirectory(crypto) # add TDDL add_subdirectory(tddl) # add kernel modules option(BUILD_DEV "Build linux kernel module" ON) if(BUILD_DEV) add_subdirectory(tpmd_dev) endif() # add executables add_subdirectory(tpmd) ================================================ FILE: ChangeLog ================================================ 2011-11-05 Mario Strasser * ChangeLog: ChangeLog updated * CMakeList.txt: minor version number updated * tpm_integrity.c: Fixed bug in TPM_Quote2; thanks go to Andreas Steffen 2011-11-12 Mario Strasser * tpmd_dev/darwin/*: Added support for OS X 10.6; thanks go to Uri Blumenthal * tpm_counter.c: Bug in TPM_IncrementCounter fixed; thanks go to Charles T 2011-11-05 Mario Strasser * ChangeLog: ChangeLog updated * CMakeList.txt: minor version number updated 2011-10-25 Mario Strasser * tpm_owner.c: set Pubek to false in TakeOwnership 2011-09-15 Mario Strasser * tpmd_dev.c: fixed byter order conversion bug for aligned memory 2011-09-09 Mario Strasser * tpm_identity.c: bug fix for MakeIdentity; thanks go to Matthew Fioravante 2011-07-19 Mario Strasser * tpm_authorization.c, tpm_cmd_handler.c, tpm_structures.h: copy secret to auth struct 2011-07-19 Mario Strasser * tpm_owner.c: error codes revised 2011-07-19 Mario Strasser * tpm_nv_storage.c: bug in NV_DefineSpace fixed; thaks go to Luigi 2011-07-09 Mario Strasser * CMakeLists.txt, crypto/*: preliminary openssl support added 2011-06-08 Mario Strasser * tpm_emulator.h, tpm_owner.c, tpmd.c: removed TPM_CONF_KEEP_PUBEK_READABLE 2011-06-04 Mario Strasser * tpm_migration.c: bug in TPM_CMK_ApproveMA fixed 2011-02-13 Mario Strasser * CMakeLists.txt: minor package version updated 2011-02-12 Mario Strasser * ChangeLog: ChangeLog updated * CMakeLists.txt: minor package version updated * tpmd_dev.c: switched to new ioctl function 2010-12-30 Mario Strasser * build.bat: Missing path for Windows 7 added 2010-10-09 Mario Strasser * tpm_capability.c: Bug in TPM_SetCapability fixed 2010-09-11 Mario Strasser * all: Open/FreeBSD compatibility fixes 2010-07-19 Mario Strasser * tpm_daa.c: Bug in TPM_LoadContext and TPM_DAA_Join/Sign fixed; thanks go toEmanuele Cesena 2010-07-05 Mario Strasser * ChangeLog: ChangeLog updated * tpmd_dev/linux/*: missing kernel header file added 2010-06-13 Mario Strasser * tpm_migration.c, tpm_cmd_handler.c, tpm_crypto.c: bugs in [CMK]MigrationBlob encoding, TPM_MigrateKey(), and TPM_CertifyKey2 fixed; thanks go to S. Tate * tpm_structures.h: bug in TPM_CERTIFY_INFO fixed; thanks go to S. Tate 2010-06-10 Mario Strasser * tpm_nv_storage.c: bug in TPM_NV_WriteValue() fixed; thanks go to Luigi Semenzato 2010-03-17 Mario Strasser * tpm_emulator_extern.[ch]: external functions changed into function pointers * tpmd/*/tpmd.c: tpmd functions updated 2010-03-12 Mario Strasser * tpm_nv_storage.c: bug in TPM_NV_DefineSpace fixed; thanks go to Luigi Semenzato * README, build.sh: build description updated 2010-02-22 Mario Strasser * tpmd_dev/darwin/*: darwin module added * Makefile: installation on Mac OS X enabled * README: README updated * ChangeLog: ChangeLog updated 2010-02-19 Mario Strasser * windows/*: several fixes * crypto/bn.c: work around for older gmp libs * tddl/*: platform independent tddl * README: README updated 2010-02-18 Mario Strasser * build.sh, buils.bat: build scripts added * tpmd.c, tpm_emulator_extern.h: log modes independent of syslog * windows/tpmd.c: tpmd for windows added * windows/control_tpmd.bat: service control function added 2010-02-16 Mario Strasser * tpm/*: MTM functions added * tpmd.c: parameter to set configuration flags added * README: README updated 2010-02-15 Mario Strasser * tpm_emulator.h, tpm_cmd_handler.c: startup configuration added * CMakeLists.txt: build of openbsd module added * tpm/*: MTM support prepared and MTM hooks added 2010-02-13 Mario Strasser * all: unused variables removed; free_TPM_DATA added 2010-02-12 Mario Strasser * tpm_marshalling.[ch]: (un)marshaling_TPM_DATA added 2010-02-11 Mario Strasser * CMakeLists.txt: installation support added * README: README updated * *.h: headers updated 2010-02-10 Mario Strasser * all: new CMake makefiles added * README: README updated * CMakeLists.txt, config.h.in: cpack support added 2010-02-09 Mario Strasser * crypto/*, tpm/*: BE* conversion functions removed * tpmd/tpmd.c: smart startup mode handling * crypto/*.h, tpm/*.h: tpm_emulator_config.h removed * tpm_testinc.c: usage of tpm_min/max removed * tpm_data.c, tpm_emulator_extern.h, tpmd.c: _file -> _storage * config.h: central config.h added * all: directory structure changed 2009-12-05 Mario Strasser * tpmd_dev/Makefile: installation patch added, thanks go to David Anderson 2009-10-05 Mario Strasser * all: numerous bug fixes to make the trousers test pass 2009-10-02 Mario Strasser * tpm_delegation.c: delegation support completed 2009-09-24 Mario Strasser * tpm_crypto.c: internal, deterministic PRNG added (for testing etc.) * tpm_authorization.c: DSAP verification added 2009-09-19 Mario Strasser * tpm_capability.c: TPM_SetCapability() added * tpm_capability.c: TPM_GetCapability() completed * ChangeLog: changelog updated 2009-09-18 Mario Strasser * tpm_commands.h: declarations and descriptions of internal functions added 2009-09-17 Mario Strasser * tpm_authorization.c: DSAP support added 2009-08-28 Mario Strasser * tpm_migration.c: CMK handling completed * tpm_owner.c: TPM_OwnerClear() updated * all: code cleanup, obsolete code removed * tpm_capability.c: capability support revised * tpm_commands.h: missing parameter added 2009-08-27 Mario Strasser * tpm_structures.h: structures updated and completed * all: major revision number incremented to 6 due to changes in the internal data structure * ChangeLog: changelog updated 2009-08-26 Mario Strasser * tpm_migration.c: bugs in CMK functionality fixed, migration support completed and enabled * tpm_storage.c: usage of default exponent in pubkey generation fixed 2009-08-25 Mario Strasser * tpm_migration.c: bugs in key migration functionality fixed 2009-08-19 Mario Strasser * tpm_migration.c: TPM_CMK_CreateBlob() and TPM_CMK_ConvertMigration() added 2009-08-13 Mario Strasser * tpm_migration.c: size_t issue fixed; thanks to E. Fleury 2009-08-10 Mario Strasser * tpm_storage.c: TPM_CreateWrapKey() updated * tpm_migration.c: TPM_CMK_CreateKey() added 2009-08-09 Mario Strasser * tpm_storage.c: tpm_decrypt and tpm_encrypt added * tpm_migration.c: initial migration support added * tpm_migration.c: CMK support added 2009-08-04 Mario Strasser * tpm_deprecated.c, tpm_migration.c: bugs fixed; thanks to M. Schmidt 2009-06-05 Mario Strasser * tpm_structures.c: bug in rsa key size computation fixed 2009-05-30 Mario Strasser * tpm_owner.c: set readPubek to false once the TPM is owned 2009-04-08 Mario Strasser * tpmd.c: missing mkdirs call added 2008-10-13 Mario Strasser * rsa.[ch]: functions to determine rsa key length added * tpm_structures.h: sizeof_RSA uses precise vales 2008-05-06 Mario Strasser * tpm_storage.c: version 1.1 compatibility fixed 2008-03-23 Mario Strasser * tpm_maintenance.c: management support added * tpm_maintenance.c: several fixes in the maintenance support * tpm_storage.c: TPM_Sealx fixed and TPM_UnSeal adapted 2008-03-22 Mario Strasser * tpm_cmd_handler.c tpm_maintenance.c: maintenance support added 2008-03-21 Mario Strasser * rsa.[ch], tpm_storage.c: TPM_Sealx added 2008-03-13 Mario Strasser * tpm_owner.c: memory leak in TPM_OwnerClear fixed 2008-03-12 Mario Strasser * rsa.c: memory leak fixed * all: NV support added 2008-03-03 Heiko Stamer * tpm_deprecated.c, tpm_marshalling.c: TPM_ChangeAuthAsymFinish() added * tpm_capability.c: supported commands changed 2008-02-21 Heiko Stamer * tpm_deprecated.c, tpm_storage.c: TPM_ChangeAuthAsymStart() added 2008-02-12 Mario Strasser * ChangeLog: changes updated for release 0.5.1 2008-01-07 Mario Strasser * tpmd_dev_openbsd/*: OpenBSD module added 2007-12-19 Heiko Stamer * tpm_cmd_handler.c, tpm_integrity.c: sig. bug in TPM_Quote2() fixed 2007-12-16 Heiko Stamer * tpm_transport.c: missing ptr initialization fixed 2007-12-15 Mario Strasser * tddl.c, tpm_emulator_config.h: support for FreeBSD/OpenBSD added 2007-12-07 Heiko Stamer * tpm_structures.h: session identifier added 2007-12-07 Heiko Stamer * tpm_cmd_handler.c, tpm_counter.c: small fixes for counters 2007-12-07 Heiko Stamer * tpm_authorization.c, tpm_eviction.c, tpm_handles.c: fixes and debug calls for TSS Test Suite (TrouSerS) 2007-12-07 Heiko Stamer * tpm_deprecated.c: fixed DIR index value, according to spec v1.2 rev 103 2007-12-05 Mario Strasser * tpmd.c: optional creation of missing directories added 2007-11-19 Mario Strasser * Makefile: make rule for tpmd_dev.rules.in added 2007-11-09 Mario Strasser * tpm_storage.c, tpm_emulator_config.h: bug in TPMLoadKey fixed 2007-09-08 Mario Strasser * Makefile: make rules for tpmd_dev.rules added 2007-09-05 Heiko Stamer * tpm_deprecated.c: minor bug fixes 2007-09-05 Heiko Stamer * tpm_deprecated.c: TPM_ChangeAuthAsymStart() updated 2007-09-02 Mario Strasser * all Makefiles: some more install fixes 2007-08-23 Mario Strasser * tpmd.c: bug in tpm_get_ticks fixed 2007-08-08 Mario Strasser * tpm_integrity.c, tpm_startup.c: bug fixes regarding localityModifier 2007-08-07 Mario Strasser * tpmd.c: effective user/group can be specified 2007-08-06 Mario Strasser * all Makefiles: install-tool based installation 2007-08-02 Mario Strasser * tpm_data.c, tpm_marshalling.c: fixes to make rev 103 changes work * tpmd_dev.rules: udev rules added 2007-08-02 Heiko Stamer * tpm_credentials.c, tpm_crypto.c, tpm_daa.c, tpm_data.c, tpm_marshalling.c, tpm_structures.h: fixes to make rev 103 changes work 2007-08-02 Mario Strasser * Makefile: soname added 2007-08-01 Mario Strasser * tddl.c, tpm_storage.c, Makefile, tpmd.c, tpmd_dev.c: default storage directories for state and sockets changed 2007-07-28 Heiko Stamer * Makefile: setting soname (FIXME: need version?) 2007-07-28 Heiko Stamer * tpm_capability.c, tpm_deprecated.c, tpm_integrity.c: fixes needed for adapting v1.2 rev 103 2007-07-27 Heiko Stamer * tpm_capability.c, tpm/tpm_commands.h, tpm_deprecated.c, tpm_structures.h: changes from v1.2 rev 103 2007-07-25 Heiko Stamer * tpm_integrity.c: fixing a specification error corrected in v1.2 rev 103 2007-07-05 Mario Strasser * tpmd.c: double free fixed, type bug fixed 2007-03-23 Mario Strasser * tpmd.c: additional tpmd parameters added 2006-12-27 Mario Strasser * Makefile, tddl.c: gcc 4.1 warnings removed 2006-12-03 Mario Strasser * Makefile: tpm_dev excluded from standard distribution 2006-12-03 Mario Strasser * all: tpm daemon and device driver library added 2006-11-29 Mario Strasser * Makefile: VERSION_SUFFIX added 2006-11-14 Mario Strasser * gmp_kernel_wrapper.c, tpm_data.c: import and export functions simplified * tpm_emulator_config.h: min/max macros renamed * tpm_data.c, tpm_cmd_handler.c, tpm_startup.c: startup/restore behavior adapted according to rev94 2006-11-12 Mario Strasser * gmp_kernel_wrapper.c: __stack_chk_fail() to GNU MP wrapper added * tpm_daa.c: size_t vs. uint32_t issue in DAA routines fixed * rsa.c, tpm_daa.c, tpm_deprecated.c, tpm/tpm_testing.c, tpm_transport.c: pointer signedness warnings fixed 2006-11-11 Mario Strasser * bn.[ch], rsa.[ch], tpm_daa.c, tpm_storage.c, tpm_testing.c: bn wrapper added * gmp_kernel_wrapper.c, linux_module.c: printf format for size_t fixed 2006-11-10 Mario Strasser * all: potential name space conflicts for global symbols solved 2006-11-07 Mario Strasser * sha1.[ch], tpm_*: some issues related to 64bit architecture and size_t fixed * rsa.c: potential bug in key generation fixed * all: advanced compiler warnings and name space collisions fixed 2006-10-25 Mario Strasser * gmp_kernel_wrapper.c, rsa.c: removed all GNU MP random routines * linux_module.c, linux_module.h, tpm_emulator_config.h: moved all host specific functions and configuration parameters from linux_module.h into tpm_emulator_config.h * tpm_audit.c, tpm_identity.c, tpm_marshalling.h, tpm_transport.c: fixed some marshalling statements which cause troubles if memory alignment is mandatory 2006-10-20 Mario Strasser * tpm_capability: inline definition changed due to interoperability reasons * tpm_cmd_handler.c: marshalling bug in TPM_Seal[x] fixed 2006-10-17 Mario Strasser * tpm_cmd_handler.c, tpm_emulator.h: meaning of out/out_size parameter for tpm_handle_command slightly modified * linux_module.c: support for storage_file parameter added * linux_module.[ch], tpm_data.c: file storage functions moved into module * all: some minor typos/bugs fixed 2006-10-11 Mario Strasser * all: redundant includes removed 2006-09-03 Heiko Stamer * tpm_capability.c: small fixes (TPM_MANUFACTURER) 2006-08-14 Mario Strasser * tpm_storage.c: required key size fixed 2006-08-06 Heiko Stamer * tpm_error.c: DAA error description added 2006-08-01 Heiko Stamer * tpm_integrity.c: TPM_Quote2() added 2006-06-23 Mario Strasser * tpm_startup.c: behaviour of ST_CLEAR and storage of persistent data adapted 2006-06-18 Heiko Stamer * tpm_identity.c: identity creation and activation, that is TPM_MakeIdentity and TPM_ActivateIdentity added 2005-12-24 Mario Strasser * tpm_transport.c, tpm_marshalling.c, tpm_structures.h: Transport session functionality added 2005-12-16 Mario Strasser * linux_module.c: ioctl() support added * tpm_capability.c: TPM_GetCapability() adapted to make it work with trousers 2005-12-09 Heiko Stamer * tpm_marshalling.c, tpm_daa.c, rsa.c: DAA functionality, that is TPM_DAA_Join and TPM_DAA_Sign added 2005-08-15 Mario Strasser * all: some typos corrected * tpm_integrity.c: bug in TPM_Extend fixed 2005-05-07 Mario Strasser * bug in TPM_SaveContext fixed 2005-04-30 Mario Strasser * tpm_digest.c: audit functionality added 2005-04-29 Mario Strasser * tpm_context.c: TPM_KeyControlOwner, TPM_SaveContext, and TPM_LoadContext added * tpm_deprecated: TPM_(Save|Load)(Key|Auth)Context added * rc4.[ch]: RC4 encryption added * rsa.c: rsa_copy_key added 2005-04-27 Mario Strasser * tpm_crypto.c: TPM_CertifyKey and TPM_CertifyKey2 added * tpm_deprecated: TPM_OwnerReadPubek, TPM_CertifySelfTest, TPM_DirWriteAuth, and TPM_DirRead added 2005-04-26 Mario Strasser * tpm_ticks.c: timing ticks functionality added * tpm_authorization.c: TPM_ChangeAuth and TPM_ChangeAuthOwner added * tpm_storage, tpm_crypto.c, tpm_integrity.c: authorization verification now considers the value of authDataUsage * tpm_storage: TPM_UnBind added 2004-10-24 Mario Strasser * Makefile: new makefile for Linux kernels > 2.5.0 build system * tpm_testing.c: replacement of some floating-point calculations with fix-point arithmetic * all: minor changes int the directory and header file structure to make the package easier portable and maintainable 2004-07-01 Mario Strasser * Initial release based on my semester thesis ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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 program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: README ================================================ _____ ____ __ __ _____ _ _ |_ _| _ \| \/ | | ____|_ __ ___ _ _| | __ _| |_ ___ _ __ | | | |_) | |\/| | _____ | _| | '_ ` _ \| | | | |/ _` | __/ _ \| '__| | | | __/| | | | |_____| | |___| | | | | | |_| | | (_| | || (_) | | |_| |_| |_| |_| |_____|_| |_| |_|\__,_|_|\__,_|\__\___/|_| TPM-Emulator v0.7 - A Software-based TPM and MTM Emulator. -------------------------------------------------------------------------- Copyright -------------------------------------------------------------------------- Copyright (C) 2009-2011 Mario Strasser. Copyright (C) 2004-2009 Mario Strasser, ETH Zurich. This program 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 program 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. Package -------------------------------------------------------------------------- The tpm emulator package comprises four main parts: a) tpmd - a user-space application that implements the actual emulator and can be accessed by means of Unix domain sockets (Unix) or named pipes (Windows). b) tpmd_dev - a kernel module that provides the device /dev/tpm for backward compatibility and forwards the received commands to tpmd (Unix and Mac OS X only). c) tddl - a TSS conform device driver library for the emulator. Compilation and Installation -------------------------------------------------------------------------- The compilation and installation of the TPM emulator package is based on the CMake build environment (version 2.6 or better) and requires that the GNU MP library (version 4.0 or better) is properly installed on your system. A working MinGW compiler suite is further required on Windows (see http://www.mingw.org/). To compile and install the package execute: # tar -xvzf tpm_emulator-X.Y.tar.gz # cd tpm_emulator-X.Y # mkdir build # cd build # cmake ../ # make # make install The script files build.sh and build.bat automate the compliation process. On Windows, the TPM emulator system service has additionally to be registered by calling: # control_tpmd.bat install MTM support can be enabled by replacing # cmake ../ with # cmake ../ -DMTM_EMULATOR=ON Startup -------------------------------------------------------------------------- In order to use the TPM emulator on Unix or Mac OS X, one has to start the TPM emulator daemon and load the TPM device forwarding module. On Linux, this is done by executing: # modprobe tpmd_dev # tpmd On Windows, the TPM emulator service can either be started with the Microsoft Management Console or with the control_tpmd.bat script: # control_tpmd.bat start # control_tpmd.bat status The startup mode of the TPM (see TPM Spec. Part 1) is defined by the startup mode argument and can either be set to clear, save (default) or deactivated. Additionally supported arguments are usage: tpmd [-d] [-f] [-s storage file] [-u unix socket name] [-o user name] [-g group name] [-h] [startup mode] d : enable debug mode f : forces the application to run in the foreground s : storage file to use (default: /var/lib/tpm/tpm_emulator-1_2_0_7) u : unix socket name to use (default: /var/run/tpm/tpmd_socket:0) o : effective user the application should run as g : effective group the application should run as h : print this help message startup mode : must be 'clear', 'save' (default) or 'deactivated and usage: tpmd.exe [-d] [-f] [-s storage file] [-u windows pipe name] [-l log file] [-h] [startup mode] d : enable debug mode f : forces the application to run in the foreground s : storage file to use (default: C:/Program Files/TPM_Emulator/tpm_emulator-1_2_0_7) u : windows named pipe name to use (default: //./pipe/tpmd:0) l : name of the log file (default: C:/Program Files/TPM_Emulator/tpmd.log) h : print this help message startup mode : must be 'clear', 'save' (default) or 'deactivated on Unix and Windows, respectively. If the emulator is started in mode save and fails to load a previously stored TPM state, it will go into fail-stop mode and has to be reloaded. Therefore, the first time the TPM emulator is started, the argument must be set to 'clear'. Recovering a TPM emulator that is in fail-stop mode is done by first deactivating it and then reloading it in mode 'clear': # tpmd deactivated # killall tpmd # tpmd clear Usage and Backward Compatibility -------------------------------------------------------------------------- The most correct and convenient way to access the tpm emulator is to use the provided device driver library (tddl). For a comprehensive description of its functionality we refer to the official TCG specification (see https://www.trustedcomputinggroup.org/specs/TSS), an example of use is given by the test application tddl/test_tddl. Note that on Windows the tddl is called ifxtpm.dll as many applications (e.g., TPM/J) expect this name and do not support alternative drivers. For backward compatibility with existing Unix applications, the kernel module tpmd_dev forwards any command sent to the device /dev/tpm to the tpm emulator daemon. In order to access the emulator directly (i.e., without using the device driver library or the device dev/tpm) all one has to do is to include the header files sys/socket.h and sys/un.h and to replace the open("/dev/tpm") call with something like: struct sockaddr_un addr; fh = socket(PF_UNIX, SOCK_STREAM, 0); if (fh < 0) { /* handle error */ } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, "/var/run/tpm/tpmd_socket:0", sizeof(addr.sun_path)-1); res = connect(fh, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)); if (res < 0) { /* handle error */ } All subsequent calls of read(), write(), and close() should work as expected. Usage Examples for TPM/J -------------------------------------------------------------------------- === Linux # modprobe tpmd_dev # tpmd -d # cd /lib # export CLASSPATH=tpmj.jar:bcprov-jdk15-131.jar:$CLASSPATH # java edu.mit.csail.tpmj.tools.TPMInfo === Mac OS X # sudo kextload /System/Library/Extensions/tpm_bridge.kext # sudo tpmd -d # cd /lib # export CLASSPATH=tpmj.jar:bcprov-jdk15-131.jar:$CLASSPATH # sudo java edu.mit.csail.tpmj.tools.TPMInfo === Windows # set PATH=%PROGRAMFILES%\TPM_Emulator;%PATH% # set PATH=%PROGRAMFILES%\TPM_Emulator\lib;%PATH% # control_tpmd.bat start # cd \lib # set CLASSPATH=tpmj.jar;bcprov-jdk15-131.jar:%CLASSPATH% # java edu.mit.csail.tpmj.tools.TPMInfo Notes -------------------------------------------------------------------------- * Since release 0.7 the emulator also runs on Darwin (Mac OS X) and on Windows; thanks go to Amit Singh and Domenic Schröder. In addition, the emulator now also supports MTM emulation; thanks go to Jan-Erik Ekberg and Markku Kylänpää from Nokia. * Since release 0.5.1 the emulator supports Free- and OpenBSD; thanks go to Sebastian Schuetz. * Since release 0.5 the kernel-based emulator (tpm_dev) is obsolete. * The name and format of the persistent-storage file has changed between release 0.2 and 0.3, 0.4 and 0.4.1., 0.5 and 0.6, and 0.6 and 0.7. * The DAA support was tested with the IBM DAA Test Suite and should work now as expected. Thanks go to Roger Zimmermann for his kindly help. Contact -------------------------------------------------------------------------- Any comments, suggestions and bug reports are welcome. Please, mention the keyword 'TPM emulator' in the subject. Peter Huewe Mario Strasser ================================================ FILE: build.bat ================================================ @echo off set BUILD_DIR=build set PATH=C:\MinGW\bin;C:\Program Files\CMake 2.8\bin;C:\Program Files (x86)\CMake 2.8\bin;%PATH% if "%1" == "clean" rmdir "%BUILD_DIR%" /S /Q if not exist "%BUILD_DIR%" mkdir "%BUILD_DIR%" cd %BUILD_DIR% cmake .. -G "MinGW Makefiles" ::cmake .. -G "MinGW Makefiles" -DMTM_EMULATOR=ON mingw32-make cd .. ================================================ FILE: build.sh ================================================ #!/bin/sh BUILD_DIR="build" if [ "$1" = "clean" ]; then rm -rf $BUILD_DIR fi if [ ! -d $BUILD_DIR ]; then mkdir $BUILD_DIR || exit 1 fi cd build cmake ../ #-DMTM_EMULATOR=ON make cd .. exit 0 ================================================ FILE: config.h.in ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: config.h.in 426 2010-02-22 17:11:58Z mast $ */ #ifndef _CONFIG_H_ #define _CONFIG_H_ /* project and build version */ #define VERSION_MAJOR ${TPM_Emulator_VERSION_MAJOR} #define VERSION_MINOR ${TPM_Emulator_VERSION_MINOR} #define VERSION_BUILD ${TPM_Emulator_VERSION_BUILD} /* TDDL and LKM configuration */ #define TPM_SOCKET_NAME "${TPM_SOCKET_NAME}" #define TPM_STORAGE_NAME "${TPM_STORAGE_NAME}" #define TPM_DEVICE_NAME "${TPM_DEVICE_NAME}" #define TPM_LOG_FILE "${TPM_LOG_FILE}" #define TPM_CMD_BUF_SIZE 4096 #endif /* _CONFIG_H_ */ ================================================ FILE: crypto/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 464 2011-07-09 14:57:41Z mast $ file(GLOB tpm_crypto_SRCS "*.[h|c]") file(GLOB bn_SRCS "bn_*.c") list(REMOVE_ITEM tpm_crypto_SRCS ${bn_SRCS}) if(USE_OPENSSL) list(APPEND tpm_crypto_SRCS "bn_openssl.c") add_library(tpm_crypto STATIC ${tpm_crypto_SRCS}) target_link_libraries(tpm_crypto crypto) else() list(APPEND tpm_crypto_SRCS "bn_gmp.c") add_library(tpm_crypto STATIC ${tpm_crypto_SRCS}) target_link_libraries(tpm_crypto gmp) endif() ================================================ FILE: crypto/bn.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: bn.h 464 2011-07-09 14:57:41Z mast $ */ #ifndef _BN_H_ #define _BN_H_ #include #include #ifdef USE_OPENSSL #include typedef BIGNUM tpm_bn_t[1]; #else #include typedef mpz_t tpm_bn_t; #endif void tpm_bn_init(tpm_bn_t a); void tpm_bn_init2(tpm_bn_t a, size_t nbits); void tpm_bn_init_set(tpm_bn_t a, tpm_bn_t val); void tpm_bn_init_set_ui(tpm_bn_t a, uint32_t val); void tpm_bn_set_ui(tpm_bn_t a, uint32_t val); void tpm_bn_clear(tpm_bn_t a); void tpm_bn_swap(tpm_bn_t a, tpm_bn_t b); uint32_t tpm_bn_bitsize(tpm_bn_t a); void tpm_bn_import(tpm_bn_t out, size_t count, int order, const void *in); void tpm_bn_export(void *out, size_t *count, int order, tpm_bn_t in); int tpm_bn_cmp(tpm_bn_t a, tpm_bn_t b); int tpm_bn_cmp_ui(tpm_bn_t a, uint32_t b); int tpm_bn_sgn(tpm_bn_t a); void tpm_bn_setbit(tpm_bn_t res, uint32_t bit); void tpm_bn_add(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b); void tpm_bn_add_ui(tpm_bn_t res, tpm_bn_t a, uint32_t b); void tpm_bn_sub(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b); void tpm_bn_sub_ui(tpm_bn_t res, tpm_bn_t a, uint32_t b); void tpm_bn_mul(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b); void tpm_bn_mod(tpm_bn_t res, tpm_bn_t a, tpm_bn_t mod); void tpm_bn_powm(tpm_bn_t res, tpm_bn_t base, tpm_bn_t exp, tpm_bn_t mod); void tpm_bn_ui_pow_ui(tpm_bn_t res, uint32_t base, uint32_t exp); void tpm_bn_fdiv_q_2exp(tpm_bn_t res, tpm_bn_t n, uint32_t b); void tpm_bn_tdiv_q(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b); void tpm_bn_gcd(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b); void tpm_bn_invert(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b); void tpm_bn_nextprime(tpm_bn_t res, tpm_bn_t a); #endif /* _BN_H_ */ ================================================ FILE: crypto/bn_gmp.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: bn_gmp.c 464 2011-07-09 14:57:41Z mast $ */ #include "bn.h" void tpm_bn_init(tpm_bn_t a) { mpz_init(a); } void tpm_bn_init2(tpm_bn_t a, size_t nbits) { mpz_init2(a, nbits + GMP_NUMB_BITS); } void tpm_bn_init_set(tpm_bn_t a, tpm_bn_t val) { mpz_init_set(a, val); } void tpm_bn_init_set_ui(tpm_bn_t a, uint32_t val) { mpz_init_set_ui(a, val); } void tpm_bn_set_ui(tpm_bn_t a, uint32_t val) { mpz_set_ui(a, val); } void tpm_bn_clear(tpm_bn_t a) { mpz_clear(a); } void tpm_bn_swap(tpm_bn_t a, tpm_bn_t b) { mpz_swap(a, b); } uint32_t tpm_bn_bitsize(tpm_bn_t a) { return mpz_sizeinbase(a, 2); } void tpm_bn_import(tpm_bn_t out, size_t count, int order, const void *in) { mpz_import(out, count, order, 1, 0, 0, in); } void tpm_bn_export(void *out, size_t *count, int order, tpm_bn_t in) { size_t count_out; mpz_export(out, &count_out, order, 1, 0, 0, in); if (count != NULL) *count = count_out; } int tpm_bn_cmp(tpm_bn_t a, tpm_bn_t b) { return mpz_cmp(a, b); } int tpm_bn_cmp_ui(tpm_bn_t a, uint32_t b) { return mpz_cmp_ui(a, b); } int tpm_bn_sgn(tpm_bn_t a) { return mpz_sgn(a); } void tpm_bn_setbit(tpm_bn_t res, uint32_t bit) { mpz_setbit(res, bit); } void tpm_bn_add(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { mpz_add(res, a, b); } void tpm_bn_add_ui(tpm_bn_t res, tpm_bn_t a, uint32_t b) { mpz_add_ui(res, a, b); } void tpm_bn_sub(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { mpz_sub(res, a, b); } void tpm_bn_sub_ui(tpm_bn_t res, tpm_bn_t a, uint32_t b) { mpz_sub_ui(res, a, b); } void tpm_bn_mul(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { mpz_mul(res, a, b); } void tpm_bn_mod(tpm_bn_t res, tpm_bn_t a, tpm_bn_t mod) { mpz_mod(res, a, mod); } void tpm_bn_powm(tpm_bn_t res, tpm_bn_t base, tpm_bn_t exp, tpm_bn_t mod) { mpz_powm(res, base, exp, mod); } void tpm_bn_ui_pow_ui(tpm_bn_t res, uint32_t base, uint32_t exp) { mpz_ui_pow_ui(res, base, exp); } void tpm_bn_fdiv_q_2exp(tpm_bn_t res, tpm_bn_t n, uint32_t b) { mpz_fdiv_q_2exp(res, n, b); } void tpm_bn_tdiv_q(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { mpz_tdiv_q(res, a, b); } void tpm_bn_gcd(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { mpz_gcd(res, a, b); } void tpm_bn_invert(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { mpz_invert(res, a, b); } void tpm_bn_nextprime(tpm_bn_t res, tpm_bn_t a) { mpz_nextprime(res, a); } ================================================ FILE: crypto/bn_openssl.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2011 Mario Strasser * * 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: bn.c 406 2010-02-19 11:08:30Z mast $ */ #include "bn.h" BN_CTX *bn_ctx = NULL; void tpm_bn_init(tpm_bn_t a) { if (bn_ctx == NULL) bn_ctx = BN_CTX_new(); BN_init(a); } void tpm_bn_init2(tpm_bn_t a, size_t nbits) { tpm_bn_init(a); BN_set_bit(a, nbits); BN_clear_bit(a, nbits); } void tpm_bn_init_set(tpm_bn_t a, tpm_bn_t val) { tpm_bn_init(a); BN_copy(a, val); } void tpm_bn_init_set_ui(tpm_bn_t a, uint32_t val) { tpm_bn_init(a); BN_set_word(a, val); } void tpm_bn_set_ui(tpm_bn_t a, uint32_t val) { BN_set_word(a, val); } void tpm_bn_clear(tpm_bn_t a) { BN_clear_free(a); } void tpm_bn_swap(tpm_bn_t a, tpm_bn_t b) { BN_swap(a, b); } uint32_t tpm_bn_bitsize(tpm_bn_t a) { return BN_num_bits(a); } void tpm_bn_import(tpm_bn_t out, size_t count, int order, const void *in) { //FIXME: reverse order if order != 1. BN_bin2bn(in, count, out); } void tpm_bn_export(void *out, size_t *count, int order, tpm_bn_t in) { //FIXME: reverse order if order != 1. BN_bn2bin(in, out); if (count != NULL) *count = BN_num_bytes(in); } int tpm_bn_cmp(tpm_bn_t a, tpm_bn_t b) { return BN_cmp(a, b); } int tpm_bn_cmp_ui(tpm_bn_t a, uint32_t b) { tpm_bn_t b2; tpm_bn_init_set_ui(b2, b); int res = tpm_bn_cmp(a, b2); tpm_bn_clear(b2); return res; } int tpm_bn_sgn(tpm_bn_t a) { if (BN_is_zero(a)) return 0; return BN_is_negative(a) ? -1 : 1; } void tpm_bn_setbit(tpm_bn_t res, uint32_t bit) { BN_set_bit(res, bit); } void tpm_bn_add(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { BN_add(res, a, b); } void tpm_bn_add_ui(tpm_bn_t res, tpm_bn_t a, uint32_t b) { BN_copy(res, a); BN_add_word(res, b); } void tpm_bn_sub(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { BN_sub(res, a, b); } void tpm_bn_sub_ui(tpm_bn_t res, tpm_bn_t a, uint32_t b) { BN_copy(res, a); BN_sub_word(res, b); } void tpm_bn_mul(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { BN_mul(res, a, b, bn_ctx); } void tpm_bn_mod(tpm_bn_t res, tpm_bn_t a, tpm_bn_t mod) { BN_mod(res, a, mod, bn_ctx); } void tpm_bn_powm(tpm_bn_t res, tpm_bn_t base, tpm_bn_t exp, tpm_bn_t mod) { BN_mod_exp(res, base, exp, mod, bn_ctx); } void tpm_bn_ui_pow_ui(tpm_bn_t res, uint32_t base, uint32_t exp) { //FIXME: BIGNUM b, e; BN_init(&b); BN_init(&e); BN_set_word(&b, base); BN_set_word(&e, exp); BN_exp(res, &b, &e, bn_ctx); BN_clear_free(&b); BN_clear_free(&e); } void tpm_bn_fdiv_q_2exp(tpm_bn_t res, tpm_bn_t n, uint32_t b) { BN_rshift(res, n, b); } void tpm_bn_tdiv_q(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { BN_div(res, NULL, a, b, bn_ctx); } void tpm_bn_gcd(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { BN_gcd(res, a, b, bn_ctx); } void tpm_bn_invert(tpm_bn_t res, tpm_bn_t a, tpm_bn_t b) { BN_mod_inverse(res, a, b, bn_ctx); } void tpm_bn_nextprime(tpm_bn_t res, tpm_bn_t a) { BN_copy(res, a); BN_set_bit(res, 0); while (!BN_is_prime(res, BN_prime_checks, NULL, bn_ctx, NULL)) { BN_add_word(res, 2); } } ================================================ FILE: crypto/hmac.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: hmac.c 364 2010-02-11 10:24:45Z mast $ */ #include "hmac.h" #include void tpm_hmac_init(tpm_hmac_ctx_t *ctx, const uint8_t *key, size_t key_len) { uint8_t tk[SHA1_DIGEST_LENGTH]; uint8_t k_ipad[HMAC_PAD_LENGTH]; int i; /* if the key is longer than 64 bytes reset it to key := hash(key) */ if (key_len > HMAC_PAD_LENGTH) { tpm_sha1_init(&ctx->ctx); tpm_sha1_update(&ctx->ctx, key, key_len); tpm_sha1_final(&ctx->ctx, tk); key = tk; key_len = SHA1_DIGEST_LENGTH; } /* start out by storing key in pads */ memset(k_ipad, 0, HMAC_PAD_LENGTH); memset(ctx->k_opad, 0, HMAC_PAD_LENGTH); memcpy(k_ipad, key, key_len); memcpy(ctx->k_opad, key, key_len); /* xor key with ipad and opad values */ for (i = 0; i < HMAC_PAD_LENGTH; i++) { k_ipad[i] ^= 0x36; ctx->k_opad[i] ^= 0x5C; } /* start inner hash */ tpm_sha1_init(&ctx->ctx); tpm_sha1_update(&ctx->ctx, k_ipad, HMAC_PAD_LENGTH); } void tpm_hmac_update(tpm_hmac_ctx_t *ctx, const uint8_t *data, size_t length) { /* update inner hash */ tpm_sha1_update(&ctx->ctx, data, length); } void tpm_hmac_final(tpm_hmac_ctx_t *ctx, uint8_t *digest) { /* complete inner hash */ tpm_sha1_final(&ctx->ctx, digest); /* perform outer hash */ tpm_sha1_init(&ctx->ctx); tpm_sha1_update(&ctx->ctx, ctx->k_opad, HMAC_PAD_LENGTH); tpm_sha1_update(&ctx->ctx, digest, SHA1_DIGEST_LENGTH); tpm_sha1_final(&ctx->ctx, digest); } ================================================ FILE: crypto/hmac.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: hmac.h 364 2010-02-11 10:24:45Z mast $ */ #ifndef _HMAC_H_ #define _HMAC_H_ #include #include #include "sha1.h" #define HMAC_PAD_LENGTH 64 typedef struct { tpm_sha1_ctx_t ctx; uint8_t k_opad[HMAC_PAD_LENGTH]; } tpm_hmac_ctx_t; void tpm_hmac_init(tpm_hmac_ctx_t *ctx, const uint8_t *key, size_t key_len); void tpm_hmac_update(tpm_hmac_ctx_t *ctx, const uint8_t *data, size_t length); void tpm_hmac_final(tpm_hmac_ctx_t *ctx, uint8_t *digest); #endif /* _HMAC_H_ */ ================================================ FILE: crypto/rc4.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: rc4.c 364 2010-02-11 10:24:45Z mast $ */ #include "rc4.h" void tpm_rc4_init(tpm_rc4_ctx_t *ctx, uint8_t *key, size_t key_len) { int i; uint8_t a, j, k; ctx->x = ctx->y = 0; for (i = 0; i < 256; i++) { ctx->state[i] = i; } for (i = j = k = 0; i < 256; i++) { a = ctx->state[i]; j += a + key[k++]; ctx->state[i] = ctx->state[j]; ctx->state[j] = a; if (k >= key_len) k = 0; } /* to strengthen the algorithm it is recommended to discard the first few (say 256) octets */ for (i = 0; i < 16; i++) { uint8_t buf[16]; tpm_rc4_crypt(ctx, buf, buf, sizeof(buf)); } } void tpm_rc4_crypt(tpm_rc4_ctx_t *ctx, uint8_t *in, uint8_t *out, size_t length) { uint8_t a, x, y, *state; x = ctx->x; y = ctx->y; state = ctx->state; while (length--) { x++; y += state[x]; a = state[x]; state[x] = state[y]; state[y] = a; a += state[x]; *out++ = *in++ ^ state[a]; } ctx->x = x; ctx->y = y; } ================================================ FILE: crypto/rc4.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: rc4.h 364 2010-02-11 10:24:45Z mast $ */ #ifndef _RC4_H_ #define _RC4_H_ #include #include typedef struct { uint8_t state[256]; uint8_t x, y; } tpm_rc4_ctx_t; void tpm_rc4_init(tpm_rc4_ctx_t *s, uint8_t *key, size_t key_len); void tpm_rc4_crypt(tpm_rc4_ctx_t *s, uint8_t *in, uint8_t *out, size_t length); #endif /* _RC4_h_ */ ================================================ FILE: crypto/rsa.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: rsa.c 364 2010-02-11 10:24:45Z mast $ */ #include "rsa.h" #include "sha1.h" #include "tpm/tpm_commands.h" static int rsa_public(tpm_rsa_public_key_t *key, const uint8_t *in, size_t in_len, uint8_t *out) { size_t t; tpm_bn_t p, c; tpm_bn_init2(p, key->size); tpm_bn_init2(c, key->size); tpm_bn_import(p, in_len, 1, in); /* c = p ^ d mod n */ tpm_bn_powm(c, p, key->e, key->n); t = tpm_bn_bitsize(c); if (t > key->size) { tpm_bn_clear(p); tpm_bn_clear(c); return -1; } t = (key->size - t) >> 3; memset(out, 0, t); tpm_bn_export(&out[t], &t, 1, c); tpm_bn_clear(p); tpm_bn_clear(c); return 0; } static int rsa_private(tpm_rsa_private_key_t *key, const uint8_t *in, size_t in_len, uint8_t *out) { size_t t; tpm_bn_t p, c, m1, m2, h; tpm_bn_init2(p, key->size); tpm_bn_init2(c, key->size); tpm_bn_import(p, in_len, 1, in); if (!key->p || !key->q || !key->u) { /* c = p ^ d mod n */ tpm_bn_powm(c, p, key->d, key->n); } else { tpm_bn_init2(m1, key->size / 2); tpm_bn_init2(m2, key->size / 2); tpm_bn_init2(h, key->size); /* m1 = p ^ (d mod (p-1)) mod p */ tpm_bn_sub_ui(h, key->p, 1); tpm_bn_mod(h, key->d, h); tpm_bn_powm(m1, p, h, key->p); /* m2 = p ^ (d mod (q-1)) mod q */ tpm_bn_sub_ui(h, key->q, 1); tpm_bn_mod(h, key->d, h); tpm_bn_powm(m2, p, h, key->q); /* h = u * ( m2 - m1 ) mod q */ tpm_bn_sub(h, m2, m1); if (tpm_bn_sgn(h) < 0) tpm_bn_add(h, h, key->q); tpm_bn_mul(h, key->u, h); tpm_bn_mod(h, h, key->q); /* c = m1 + h * p */ tpm_bn_mul(h, h, key->p); tpm_bn_add(c, m1, h); tpm_bn_clear(m1); tpm_bn_clear(m2); tpm_bn_clear(h); } t = tpm_bn_bitsize(c); if (t > key->size) { tpm_bn_clear(p); tpm_bn_clear(c); return -1; } t = (key->size - t) >> 3; memset(out, 0, t); tpm_bn_export(&out[t], &t, 1, c); tpm_bn_clear(p); tpm_bn_clear(c); return 0; } static int rsa_test_key(tpm_rsa_private_key_t *key) { tpm_bn_t a, b, t; int res = 0; tpm_bn_init2(a, key->size); tpm_bn_init2(b, key->size); tpm_bn_init2(t, key->size); tpm_bn_set_ui(t, 0xdeadbeef); tpm_bn_powm(a, t, key->e, key->n); tpm_bn_powm(b, a, key->d, key->n); if (tpm_bn_cmp(t, b) != 0) res = -1; tpm_bn_powm(a, t, key->d, key->n); tpm_bn_powm(b, a, key->e, key->n); if (tpm_bn_cmp(t, b) != 0) res = -1; tpm_bn_clear(a); tpm_bn_clear(b); tpm_bn_clear(t); return res; } int tpm_rsa_import_key(tpm_rsa_private_key_t *key, int endian, const uint8_t *n, size_t n_len, const uint8_t *e, size_t e_len, const uint8_t *p, const uint8_t *q) { tpm_bn_t t1, t2, phi; if (n == NULL || n_len == 0 || (p == NULL && q == NULL)) return -1; /* init key */ key->size = n_len << 3; if (e == NULL || e_len == 0) { tpm_bn_init_set_ui(key->e, 65537); } else { tpm_bn_init2(key->e, e_len << 3); tpm_bn_import(key->e, e_len, endian, e); } tpm_bn_init2(key->n, key->size); tpm_bn_init2(key->p, key->size / 2); tpm_bn_init2(key->q, key->size / 2); tpm_bn_init2(key->d, key->size); tpm_bn_init2(key->u, key->size / 2); tpm_bn_init2(t1, key->size / 2); tpm_bn_init2(t2, key->size / 2); tpm_bn_init2(phi, key->size); /* import values */ tpm_bn_import(key->n, n_len, endian, n); if (p != NULL) tpm_bn_import(key->p, n_len / 2, endian, p); if (q != NULL) tpm_bn_import(key->q, n_len / 2, endian, q); if (p == NULL) tpm_bn_tdiv_q(key->p, key->n, key->q); if (q == NULL) tpm_bn_tdiv_q(key->q, key->n, key->p); /* p shall be smaller than q */ if (tpm_bn_cmp(key->p, key->q) > 0) tpm_bn_swap(key->p, key->q); /* calculate missing values */ tpm_bn_sub_ui(t1, key->p, 1); tpm_bn_sub_ui(t2, key->q, 1); tpm_bn_mul(phi, t1, t2); tpm_bn_invert(key->d, key->e, phi); tpm_bn_invert(key->u, key->p, key->q); /* release helper variables */ tpm_bn_clear(t1); tpm_bn_clear(t2); tpm_bn_clear(phi); /* test key */ if (rsa_test_key(key) != 0) { tpm_rsa_release_private_key(key); return -1; } return 0; } void tpm_rsa_copy_key(tpm_rsa_private_key_t *dst, tpm_rsa_private_key_t *src) { tpm_bn_init_set(dst->n, src->n); tpm_bn_init_set(dst->e, src->e); tpm_bn_init_set(dst->d, src->d); tpm_bn_init_set(dst->p, src->p); tpm_bn_init_set(dst->q, src->q); tpm_bn_init_set(dst->u, src->u); dst->size = src->size; } int tpm_rsa_import_public_key(tpm_rsa_public_key_t *key, int endian, const uint8_t *n, size_t n_len, const uint8_t *e, size_t e_len) { if (n == NULL || n_len == 0) return -1; /* init key */ key->size = n_len << 3; if (e == NULL || e_len == 0) { tpm_bn_init_set_ui(key->e, 65537); } else { tpm_bn_init2(key->e, e_len << 3); tpm_bn_import(key->e, e_len, endian, e); } tpm_bn_init2(key->n, key->size); /* import values */ tpm_bn_import(key->n, n_len, endian, n); return 0; } static void rsa_tpm_bn_random(tpm_bn_t a, size_t nbits) { size_t size = nbits >> 3; uint8_t buf[size]; tpm_get_random_bytes(buf, size); tpm_bn_import(a, size, 1, buf); } int tpm_rsa_generate_key(tpm_rsa_private_key_t *key, uint16_t key_size) { tpm_bn_t e, p, q, n, t1, t2, phi, d, u; /* bit_size must be a multiply of eight */ while (key_size & 0x07) key_size++; /* we use e = 65537 */ tpm_bn_init_set_ui(e, 65537); tpm_bn_init2(p, key_size / 2); tpm_bn_init2(q, key_size / 2); tpm_bn_init2(n, key_size); tpm_bn_init2(t1, key_size / 2); tpm_bn_init2(t2, key_size / 2); tpm_bn_init2(phi, key_size); tpm_bn_init2(d, key_size); tpm_bn_init2(u, key_size / 2); do { /* get prime p */ rsa_tpm_bn_random(p, key_size / 2); tpm_bn_setbit(p, 0); tpm_bn_setbit(p, key_size / 2 - 1); tpm_bn_setbit(p, key_size / 2 - 2); tpm_bn_nextprime(p, p); tpm_bn_sub_ui(t1, p, 1); tpm_bn_gcd(phi, e, t1); if (tpm_bn_cmp_ui(phi, 1) != 0) continue; /* get prime q */ rsa_tpm_bn_random(q, key_size / 2); tpm_bn_setbit(q, 0); tpm_bn_setbit(q, key_size / 2 - 1); tpm_bn_setbit(q, key_size / 2 - 2); tpm_bn_nextprime(q, q); tpm_bn_sub_ui(t2, q, 1); tpm_bn_gcd(phi, e, t1); if (tpm_bn_cmp_ui(phi, 1) != 0) continue; /* p shall be smaller than q */ if (tpm_bn_cmp(p, q) > 0) tpm_bn_swap(p, q); /* calculate the modulus */ tpm_bn_mul(n, p, q); } while (tpm_bn_bitsize(n) != key_size); /* calculate Euler totient: phi = (p-1)(q-1) */ tpm_bn_mul(phi, t1, t2); /* calculate the secret key d = e^(-1) mod phi */ tpm_bn_invert(d, e, phi); /* calculate the inverse of p and q (used for chinese remainder theorem) */ tpm_bn_invert(u, p, q); /* setup private key */ tpm_bn_init_set(key->n, n); tpm_bn_init_set(key->e, e); tpm_bn_init_set(key->p, p); tpm_bn_init_set(key->q, q); tpm_bn_init_set(key->d, d); tpm_bn_init_set(key->u, u); key->size = key_size; /* release helper variables */ tpm_bn_clear(e); tpm_bn_clear(p); tpm_bn_clear(q); tpm_bn_clear(n); tpm_bn_clear(t1); tpm_bn_clear(t2); tpm_bn_clear(phi); tpm_bn_clear(d); tpm_bn_clear(u); /* test key */ if (rsa_test_key(key) != 0) { tpm_rsa_release_private_key(key); return -1; } return 0; } void tpm_rsa_release_private_key(tpm_rsa_private_key_t *key) { tpm_bn_clear(key->n); tpm_bn_clear(key->e); tpm_bn_clear(key->p); tpm_bn_clear(key->q); tpm_bn_clear(key->d); tpm_bn_clear(key->u); memset(key, 0, sizeof(*key)); } void tpm_rsa_release_public_key(tpm_rsa_public_key_t *key) { tpm_bn_clear(key->n); tpm_bn_clear(key->e); memset(key, 0, sizeof(*key)); } void tpm_rsa_export_modulus(tpm_rsa_private_key_t *key, uint8_t *modulus, size_t *length) { tpm_bn_export(modulus, length, 1, key->n); } void tpm_rsa_export_exponent(tpm_rsa_private_key_t *key, uint8_t *exponent, size_t *length) { tpm_bn_export(exponent, length, 1, key->e); } void tpm_rsa_export_prime1(tpm_rsa_private_key_t *key, uint8_t *prime, size_t *length) { tpm_bn_export(prime, length, 1, key->p); } void tpm_rsa_export_prime2(tpm_rsa_private_key_t *key, uint8_t *prime, size_t *length) { tpm_bn_export(prime, length, 1, key->q); } void tpm_rsa_export_public_modulus(tpm_rsa_public_key_t *key, uint8_t *modulus, size_t *length) { tpm_bn_export(modulus, length, 1, key->n); } void tpm_rsa_export_public_exponent(tpm_rsa_public_key_t *key, uint8_t *exponent, size_t *length) { tpm_bn_export(exponent, length, 1, key->e); } size_t tpm_rsa_modulus_length(tpm_rsa_private_key_t *key) { return (tpm_bn_bitsize(key->n) + 7) >> 3; } size_t tpm_rsa_exponent_length(tpm_rsa_private_key_t *key) { return (tpm_bn_bitsize(key->e) + 7) >> 3; } size_t tpm_rsa_prime1_length(tpm_rsa_private_key_t *key) { return (tpm_bn_bitsize(key->p) + 7) >> 3; } size_t tpm_rsa_prime2_length(tpm_rsa_private_key_t *key) { return (tpm_bn_bitsize(key->q) + 7) >> 3; } size_t tpm_rsa_public_modulus_length(tpm_rsa_public_key_t *key) { return (tpm_bn_bitsize(key->n) + 7) >> 3; } size_t tpm_rsa_public_exponent_length(tpm_rsa_public_key_t *key) { return (tpm_bn_bitsize(key->e) + 7) >> 3; } void tpm_rsa_mask_generation(const uint8_t *seed, size_t seed_len, uint8_t *data, size_t data_len) { tpm_sha1_ctx_t ctx; uint8_t mask[SHA1_DIGEST_LENGTH]; uint32_t i, len, counter = 0; while (data_len > 0) { tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, seed, seed_len); tpm_sha1_update_be32(&ctx, counter); tpm_sha1_final(&ctx, mask); counter++; len = (data_len < SHA1_DIGEST_LENGTH) ? data_len : SHA1_DIGEST_LENGTH; for (i = 0; i < len; i++) *data++ ^= mask[i]; data_len -= len; } } static int encode_message(int type, const uint8_t *data, size_t data_len, uint8_t *msg, size_t msg_len) { size_t i; tpm_sha1_ctx_t ctx; /* encode message according to type */ switch (type) { case RSA_SSA_PKCS1_SHA1: /* EM = 0x00||0x01||0xff-pad||0x00||SHA-1 DER header||SHA-1 digest */ if (msg_len < 35 + 11) return -1; msg[0] = 0x00; msg[1] = 0x01; memset(&msg[2], 0xff, msg_len - 38); msg[msg_len - 36] = 0x00; memcpy(&msg[msg_len - 35], "\x30\x21\x30\x09\x06\x05\x2b" "\x0e\x03\x02\x1a\x05\x00\x04\x14", 15); tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, data, data_len); tpm_sha1_final(&ctx, &msg[msg_len - 20]); break; case RSA_SSA_PKCS1_SHA1_RAW: /* EM = 0x00||0x01||0xff-pad||0x00||SHA-1 DER header||SHA-1 digest */ if (msg_len < 35 + 11 || data_len != 20) return -1; msg[0] = 0x00; msg[1] = 0x01; memset(&msg[2], 0xff, msg_len - 38); msg[msg_len - 36] = 0x00; memcpy(&msg[msg_len - 35], "\x30\x21\x30\x09\x06\x05\x2b" "\x0e\x03\x02\x1a\x05\x00\x04\x14", 15); memcpy(&msg[msg_len - 20], data, data_len); break; case RSA_SSA_PKCS1_DER: /* EM = 0x00||0x01||0xff-pad||0x00||DER encoded data */ if (msg_len < data_len + 11) return -1; msg[0] = 0x00; msg[1] = 0x01; memset(&msg[2], 0xff, msg_len - data_len - 3); msg[msg_len - data_len - 1] = 0x00; memcpy(&msg[msg_len - data_len], data, data_len); break; case RSA_ES_PKCSV15: /* EM = 0x00||0x02||nonzero random-pad||0x00||data */ if (msg_len < data_len + 11) return -1; msg[0] = 0x00; msg[1] = 0x02; tpm_get_random_bytes(&msg[2], msg_len - data_len - 3); for (i = 2; i < msg_len - data_len; i++) while (!msg[i]) tpm_get_random_bytes(&msg[i], 1); msg[msg_len - data_len - 1] = 0x00; memcpy(&msg[msg_len - data_len], data, data_len); break; case RSA_ES_OAEP_SHA1: /* DB = SHA-1("TCPA")||0x00-pad||0x01||data seed = random value of size SHA1_DIGEST_LENGTH masked-seed = seed xor MFG(seed, seed_len) masked-DB = DB xor MFG(seed, DB_len) EM = 0x00||masked-seed||masked-DB */ if (msg_len < data_len + 2 * SHA1_DIGEST_LENGTH + 2) return -1; msg[0] = 0x00; tpm_get_random_bytes(&msg[1], SHA1_DIGEST_LENGTH); tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, (uint8_t*)"TCPA", 4); tpm_sha1_final(&ctx, &msg[1 + SHA1_DIGEST_LENGTH]); memset(&msg[1 + 2 * SHA1_DIGEST_LENGTH], 0x00, msg_len - data_len - 2 * SHA1_DIGEST_LENGTH - 2); msg[msg_len - data_len - 1] = 0x01; memcpy(&msg[msg_len - data_len], data, data_len); tpm_rsa_mask_generation(&msg[1], SHA1_DIGEST_LENGTH, &msg[1 + SHA1_DIGEST_LENGTH], msg_len - SHA1_DIGEST_LENGTH - 1); tpm_rsa_mask_generation(&msg[1 + SHA1_DIGEST_LENGTH], msg_len - SHA1_DIGEST_LENGTH - 1, &msg[1], SHA1_DIGEST_LENGTH); break; case RSA_ES_PLAIN: /* EM = data */ if (msg_len != data_len) return -1; if (msg != data) memcpy(msg, data, data_len); break; default: /* unsupported encoding method */ return -1; } return 0; } static int decode_message(int type, uint8_t *msg, size_t msg_len, uint8_t *data, size_t *data_len) { size_t i; tpm_sha1_ctx_t ctx; /* decode message according to type */ switch (type) { case RSA_ES_PKCSV15: /* EM = 0x00||0x02||nonzero random-pad||0x00||data */ if (msg_len < 11) return -1; if (msg[0] != 0x00 || msg[1] != 0x02) return -1; for (i = 2; i < msg_len && msg[i]; i++); if (i < 10 || i >= msg_len) return -1; *data_len = msg_len - i - 1; memmove(data, &msg[i + 1], *data_len); break; case RSA_ES_OAEP_SHA1: /* DB = SHA-1("TCPA")||0x00-pad||0x01||data seed = random value of size SHA1_DIGEST_LENGTH masked-seed = seed xor MFG(seed, seed_len) masked-DB = DB xor MFG(seed, DB_len) EM = 0x00||masked-seed||masked-DB */ if (msg_len < 2 + 2 * SHA1_DIGEST_LENGTH) return -1; if (msg[0] != 0x00) return -1; tpm_rsa_mask_generation(&msg[1 + SHA1_DIGEST_LENGTH], msg_len - SHA1_DIGEST_LENGTH - 1, &msg[1], SHA1_DIGEST_LENGTH); tpm_rsa_mask_generation(&msg[1], SHA1_DIGEST_LENGTH, &msg[1 + SHA1_DIGEST_LENGTH], msg_len - SHA1_DIGEST_LENGTH - 1); tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, (uint8_t*)"TCPA", 4); tpm_sha1_final(&ctx, &msg[1]); if (memcmp(&msg[1], &msg[1 + SHA1_DIGEST_LENGTH], SHA1_DIGEST_LENGTH) != 0) return -1; for (i = 1 + 2 * SHA1_DIGEST_LENGTH; i < msg_len && !msg[i]; i++); if (i >= msg_len || msg[i] != 0x01) return -1; *data_len = msg_len - i - 1; memmove(data, &msg[i + 1], *data_len); break; case RSA_ES_PLAIN: /* EM = data */ *data_len = msg_len; if (msg != data) memcpy(msg, data, msg_len); break; default: /* unsupported encoding method */ return -1; } return 0; } int tpm_rsa_sign(tpm_rsa_private_key_t *key, int type, const uint8_t *data, size_t data_len, uint8_t *sig) { size_t sig_len = key->size >> 3; /* encode message */ if (encode_message(type, data, data_len, sig, sig_len) != 0) return -1; /* sign encoded message */ if (rsa_private(key, sig, sig_len, sig) != 0) return -1; return 0; } int tpm_rsa_verify(tpm_rsa_public_key_t *key, int type, const uint8_t *data, size_t data_len, uint8_t *sig) { size_t sig_len = key->size >> 3; uint8_t msg_a[sig_len]; uint8_t msg_b[sig_len]; /* encode message */ if (encode_message(type, data, data_len, msg_a, sig_len) != 0) return -1; /* decrypt signature */ if (rsa_public(key, sig, sig_len, msg_b) != 0) return -1; /* compare messages */ return (memcmp(msg_a, msg_b, sig_len) == 0) ? 0 : 1; } int tpm_rsa_decrypt(tpm_rsa_private_key_t *key, int type, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { *out_len = key->size >> 3; if (in_len != *out_len || in_len < 11) return -1; /* decrypt message */ if (rsa_private(key, in, in_len, out) != 0) return -1; /* decode message */ if (decode_message(type, out, *out_len, out, out_len) != 0) return -1; return 0; } int tpm_rsa_encrypt(tpm_rsa_public_key_t *key, int type, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { *out_len = key->size >> 3; /* encode message */ if (encode_message(type, in, in_len, out, *out_len) != 0) return -1; /* encrypt encoded message */ if (rsa_public(key, out, *out_len, out) != 0) return -1; return 0; } ================================================ FILE: crypto/rsa.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: rsa.h 364 2010-02-11 10:24:45Z mast $ */ #ifndef _RSA_H_ #define _RSA_H_ #include #include #include "bn.h" typedef struct { tpm_bn_t n; tpm_bn_t e; tpm_bn_t d; tpm_bn_t p; tpm_bn_t q; tpm_bn_t u; uint16_t size; } tpm_rsa_private_key_t; typedef struct { tpm_bn_t n; tpm_bn_t e; uint16_t size; } tpm_rsa_public_key_t; enum { RSA_ES_PKCSV15, RSA_ES_OAEP_SHA1, RSA_ES_PLAIN, RSA_SSA_PKCS1_SHA1, RSA_SSA_PKCS1_SHA1_RAW, RSA_SSA_PKCS1_DER }; enum { RSA_LSB_FIRST = -1, RSA_MSB_FIRST = 1 }; #define TPM_RSA_EXTRACT_PUBLIC_KEY(priv_key, pub_key) { \ tpm_bn_init_set(pub_key.n, priv_key.n); \ tpm_bn_init_set(pub_key.e, priv_key.e); \ pub_key.size = priv_key.size; } int tpm_rsa_import_key(tpm_rsa_private_key_t *key, int endian, const uint8_t *n, size_t n_len, const uint8_t *e, size_t e_len, const uint8_t *p, const uint8_t *q); void tpm_rsa_copy_key(tpm_rsa_private_key_t *dst, tpm_rsa_private_key_t *src); int tpm_rsa_import_public_key(tpm_rsa_public_key_t *key, int endian, const uint8_t *n, size_t n_len, const uint8_t *e, size_t e_len); int tpm_rsa_generate_key(tpm_rsa_private_key_t *key, uint16_t key_size); void tpm_rsa_release_private_key(tpm_rsa_private_key_t *key); void tpm_rsa_release_public_key(tpm_rsa_public_key_t *key); void tpm_rsa_export_modulus(tpm_rsa_private_key_t *key, uint8_t *modulus, size_t *length); void tpm_rsa_export_exponent(tpm_rsa_private_key_t *key, uint8_t *exponent, size_t *length); void tpm_rsa_export_prime1(tpm_rsa_private_key_t *key, uint8_t *prime, size_t *length); void tpm_rsa_export_prime2(tpm_rsa_private_key_t *key, uint8_t *prime, size_t *length); size_t tpm_rsa_modulus_length(tpm_rsa_private_key_t *key); size_t tpm_rsa_exponent_length(tpm_rsa_private_key_t *key); size_t tpm_rsa_prime1_length(tpm_rsa_private_key_t *key); size_t tpm_rsa_prime2_length(tpm_rsa_private_key_t *key); void tpm_rsa_mask_generation(const uint8_t *seed, size_t seed_len, uint8_t *data, size_t data_len); void tpm_rsa_export_public_modulus(tpm_rsa_public_key_t *key, uint8_t *modulus, size_t *length); void tpm_rsa_export_public_exponent(tpm_rsa_public_key_t *key, uint8_t *exponent, size_t *length); size_t tpm_rsa_public_modulus_length(tpm_rsa_public_key_t *key); size_t tpm_rsa_public_exponent_length(tpm_rsa_public_key_t *key); /* Note: Input and output areas MUST NOT overlap (i.e., one can't use the same buffer for data and sig or in and out). */ int tpm_rsa_sign(tpm_rsa_private_key_t *key, int type, const uint8_t *data, size_t data_len, uint8_t *sig); int tpm_rsa_verify(tpm_rsa_public_key_t *key, int type, const uint8_t *data, size_t data_len, uint8_t *sig); int tpm_rsa_decrypt(tpm_rsa_private_key_t *key, int type, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); int tpm_rsa_encrypt(tpm_rsa_public_key_t *key, int type, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); #endif /* _RSA_H_ */ ================================================ FILE: crypto/sha1.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: sha1.c 364 2010-02-11 10:24:45Z mast $ */ #include "sha1.h" #include /* This code is based on Steve Reid's public domain implementation. */ #define rol(v,b) (((v) << (b)) | ((v) >> (32 - (b)))) #ifdef __BIG_ENDIAN__ #define B0(i) (buf[i] = buf[i]) #else #define B0(i) (buf[i] = (((buf[i] & 0xff000000) >> 24) \ | ((buf[i] & 0x00ff0000) >> 8) \ | ((buf[i] & 0x0000ff00) << 8) \ | ((buf[i] & 0x000000ff) << 24))) #endif #define B1(i) (buf[i & 15] = rol(buf[i & 15] ^ buf[(i-14) & 15] \ ^ buf[(i-8) & 15] ^ buf[(i-3) & 15], 1)) #define F0(x,y,z) ((x & (y ^ z)) ^ z) #define F1(x,y,z) (x ^ y ^ z) #define F2(x,y,z) (((x | y) & z) | (x & y)) #define R0(a,b,c,d,e,i) e += F0(b,c,d) + B0(i) + 0x5A827999 + rol(a,5); b = rol(b,30); #define R1(a,b,c,d,e,i) e += F0(b,c,d) + B1(i) + 0x5A827999 + rol(a,5); b = rol(b,30); #define R2(a,b,c,d,e,i) e += F1(b,c,d) + B1(i) + 0x6ED9EBA1 + rol(a,5); b = rol(b,30); #define R3(a,b,c,d,e,i) e += F2(b,c,d) + B1(i) + 0x8F1BBCDC + rol(a,5); b = rol(b,30); #define R4(a,b,c,d,e,i) e += F1(b,c,d) + B1(i) + 0xCA62C1D6 + rol(a,5); b = rol(b,30); static void tpm_sha1_transform(uint32_t h[5], const uint8_t data[64]) { uint32_t a, b, c, d, e; uint32_t buf[16]; /* copy state and data*/ a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4]; memcpy(buf, data, 64); /* unrolled sha-1 rounds */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* update state */ h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; /* overwrite all used variables */ a = b = c = d = e = 0; memset(buf, 0, 64); } void tpm_sha1_init(tpm_sha1_ctx_t *ctx) { /* initialise with sha-1 constants */ ctx->h[0] = 0x67452301; ctx->h[1] = 0xEFCDAB89; ctx->h[2] = 0x98BADCFE; ctx->h[3] = 0x10325476; ctx->h[4] = 0xC3D2E1F0; ctx->count_lo = ctx->count_hi = 0; } void tpm_sha1_update(tpm_sha1_ctx_t *ctx, const uint8_t *data, size_t length) { size_t buf_off = (ctx->count_lo >> 3) & 63; size_t data_off = 0; /* add data */ if (length + buf_off >= 64) { data_off = 64 - buf_off; memcpy(&ctx->buf[buf_off], data, data_off); tpm_sha1_transform(ctx->h, ctx->buf); while (data_off + 64 <= length) { tpm_sha1_transform(ctx->h, &data[data_off]); data_off += 64; } buf_off = 0; } memcpy(&ctx->buf[buf_off], &data[data_off], length - data_off); /* update counter */ buf_off = ctx->count_lo; ctx->count_lo += length << 3; if (ctx->count_lo < buf_off) ctx->count_hi++; ctx->count_hi += length >> 29; } void tpm_sha1_update_be32(tpm_sha1_ctx_t *ctx, uint32_t data) { uint8_t buf[4]; buf[0] = (data >> 24) & 0xff; buf[1] = (data >> 16) & 0xff; buf[2] = (data >> 8) & 0xff; buf[3] = (data >> 0) & 0xff; tpm_sha1_update(ctx, buf, 4); } void tpm_sha1_final(tpm_sha1_ctx_t *ctx, uint8_t digest[SHA1_DIGEST_LENGTH]) { uint8_t d, counter[8]; /* setup counter */ for (d = 0; d < 4; d++) { counter[d ] = (ctx->count_hi >> (24 - d * 8)) & 0xff; counter[d + 4] = (ctx->count_lo >> (24 - d * 8)) & 0xff; } /* add padding */ d = 0x80; tpm_sha1_update(ctx, &d, 1); d = 0x00; while ((ctx->count_lo & (63 * 8)) != (56 * 8)) tpm_sha1_update(ctx, &d, 1); /* add counter */ tpm_sha1_update(ctx, counter, 8); for (d = 0; d < SHA1_DIGEST_LENGTH; d++) digest[d] = (uint8_t)(ctx->h[d >> 2] >> (8 * (3 - (d & 3))) & 0xff); /* overwrite all used variables */ memset(ctx, 0, sizeof(*ctx)); memset(counter, 0, sizeof(counter)); } ================================================ FILE: crypto/sha1.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: sha1.h 364 2010-02-11 10:24:45Z mast $ */ #ifndef _SHA1_H_ #define _SHA1_H_ #include #include #define SHA1_DIGEST_LENGTH 20 typedef struct { uint32_t h[5]; uint32_t count_lo, count_hi; uint8_t buf[64]; } tpm_sha1_ctx_t; void tpm_sha1_init(tpm_sha1_ctx_t *ctx); void tpm_sha1_update(tpm_sha1_ctx_t *ctx, const uint8_t *data, size_t length); void tpm_sha1_update_be32(tpm_sha1_ctx_t *ctx, uint32_t data); void tpm_sha1_final(tpm_sha1_ctx_t *ctx, uint8_t digest[SHA1_DIGEST_LENGTH]); #endif /* _SHA1_H_ */ ================================================ FILE: mtm/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 376 2010-02-16 14:51:42Z mast $ add_definitions(-DMTM_EMULATOR) file(GLOB tpm_SRCS ../tpm/tpm_cmd_handler.c ../tpm/tpm_data.c) file(GLOB mtm_SRCS "*.[h|c]") add_library(mtm STATIC ${mtm_SRCS} ${tpm_SRCS}) ================================================ FILE: mtm/mtm_capability.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_structures.h" #include "mtm_marshalling.h" #include "mtm_data.h" #include "tpm/tpm_data.h" #include "tpm/tpm_commands.h" static inline TPM_RESULT return_UINT32(UINT32 *respSize, BYTE **resp, UINT32 value) { UINT32 len = *respSize = 4; BYTE *ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, value)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; } static 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; } #define return_BYTE return_BOOL static TPM_RESULT cap_ord(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_COMMAND_CODE ord; if (tpm_unmarshal_TPM_COMMAND_CODE(&subCap, &subCapSize, &ord)) return TPM_BAD_MODE; switch (ord) { case MTM_ORD_InstallRIM: case MTM_ORD_LoadVerificationKey: case MTM_ORD_LoadVerificationRootKeyDisable: case MTM_ORD_VerifyRIMCert: case MTM_ORD_VerifyRIMCertAndExtend: case MTM_ORD_IncrementBootstrapCounter: case MTM_ORD_SetVerifiedPCRSelection: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_mtm_permanent_data(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { UINT32 subCapVal, len; BYTE* ptr; /* unmarshal subCap */ if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &subCapVal) != 0) return TPM_BAD_PARAMETER; switch (subCapVal) { case 1: return TPM_FAIL; break; case 2: *respSize = len = sizeof_TPM_PCR_SELECTION(mtmData.permanent.data.verifiedPCRs); *resp = ptr = tpm_malloc(*respSize); if (*resp == NULL || tpm_marshal_TPM_PCR_SELECTION(&ptr, &len, &mtmData.permanent.data.verifiedPCRs)) { tpm_free(*resp); return TPM_FAIL; } error("[TPM_CAP_MTM_PERMANENT_DATA] SubCap 2 not Implemented"); return TPM_FAIL; // TODO not implemented. case 3: return return_UINT32(respSize, resp, tpmData.permanent.data.counters[MTM_COUNTER_SELECT_BOOTSTRAP].counter); case 4: return return_UINT32(respSize, resp, mtmData.permanent.data.counterRimProtectId); case 5: return return_UINT32(respSize, resp, mtmData.permanent.data.counterStorageProtectId); case 6: return return_BYTE(respSize, resp, mtmData.permanent.data.specMajor); case 7: return return_BYTE(respSize, resp, mtmData.permanent.data.specMinor); case 8: return return_BYTE(respSize, resp, mtmData.permanent.data.loadVerificationKeyMethods); default: return TPM_BAD_PARAMETER; } return TPM_SUCCESS; } TPM_RESULT MTM_GetCapability(TPM_CAPABILITY_AREA capArea, UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { info("MTM_GetCapability()"); switch (capArea) { case TPM_CAP_ORD: debug("[MTM_CAP_ORD]"); TPM_RESULT res = cap_ord(subCapSize, subCap, respSize, resp); if (res == TPM_SUCCESS && resp[0] == FALSE) { res = TPM_GetCapability(capArea, subCapSize, subCap, respSize, resp); } return res; case TPM_CAP_MTM_PERMANENT_DATA: debug("[TPM_CAP_MTM_PERMANENT_DATA]"); return cap_mtm_permanent_data(subCapSize, subCap, respSize, resp); default: return TPM_GetCapability(capArea, subCapSize, subCap, respSize, resp); } } ================================================ FILE: mtm/mtm_cmd_handler.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * Copyright (C) 2007 Jan-Erik Ekberg , * Nokia Corporation and/or its subsidiary(-ies) * * 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$ */ #include "mtm_commands.h" #include "mtm_marshalling.h" extern void tpm_compute_in_param_digest(TPM_REQUEST *req); 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 TPM_RESULT execute_MTM_LoadVerificationRootKeyDisable(TPM_REQUEST *req, TPM_RESPONSE *rsp) { TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ res = MTM_LoadVerificationRootKeyDisable(); /* marshal output */ rsp->paramSize = 0; rsp->param = NULL; return res; } static TPM_RESULT execute_MTM_VerifyRIMCert(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 rimCertSize; TPM_RIM_CERTIFICATE rimCert; TPM_VERIFICATION_KEY_HANDLE rimKey; 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_VerifyRIMCert(&rimCert, rimKey); /* marshal output */ rsp->paramSize = len = 0; rsp->param = ptr = NULL; return res; } 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; } static TPM_RESULT execute_MTM_IncrementBootstrapCounter(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 rimCertSize; TPM_RIM_CERTIFICATE rimCert; TPM_VERIFICATION_KEY_HANDLE rimKey; 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_IncrementBootstrapCounter(&rimCert, rimKey); /* marshal output */ rsp->paramSize = len = 0; rsp->param = ptr = NULL; return res; } static TPM_RESULT execute_MTM_SetVerifiedPCRSelection(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PCR_SELECTION verifiedSelection; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PCR_SELECTION(&ptr, &len, &verifiedSelection) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = MTM_SetVerifiedPCRSelection(&verifiedSelection, &req->auth1); /* marshal output */ rsp->paramSize = len = 0; rsp->param = ptr = NULL; return res; } TPM_RESULT mtm_execute_command(TPM_REQUEST *req, TPM_RESPONSE *rsp) { TPM_RESULT res; /* handle command ordinal */ switch (req->ordinal) { case MTM_ORD_InstallRIM: debug("[MTM_ORD_InstallRIM]"); res = execute_MTM_InstallRIM(req, rsp); break; case MTM_ORD_LoadVerificationKey: debug("[MTM_ORD_LoadVerificationKey]"); res = execute_MTM_LoadVerificationKey(req, rsp); break; case MTM_ORD_LoadVerificationRootKeyDisable: debug("[MTM_ORD_LoadVerificationRootKeyDisable]"); res = execute_MTM_LoadVerificationRootKeyDisable(req, rsp); break; case MTM_ORD_VerifyRIMCert: debug("[MTM_ORD_VerifyRIMCert]"); res = execute_MTM_VerifyRIMCert(req, rsp); break; case MTM_ORD_VerifyRIMCertAndExtend: debug("[MTM_ORD_VerifyRIMCertAndExtend]"); res = execute_MTM_VerifyRIMCertAndExtend(req, rsp); break; case MTM_ORD_IncrementBootstrapCounter: debug("[MTM_ORD_IncrementBootstrapCounter]"); res = execute_MTM_IncrementBootstrapCounter(req, rsp); break; case MTM_ORD_SetVerifiedPCRSelection: debug("[MTM_ORD_SetVerifiedPCRSelection]"); res = execute_MTM_SetVerifiedPCRSelection(req, rsp); break; default: res = TPM_BAD_ORDINAL; break; } return res; } ================================================ FILE: mtm/mtm_commands.h ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * Copyright (C) 2007 Jan-Erik Ekberg , * Nokia Corporation and/or its subsidiary(-ies) * * 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$ */ #ifndef _MTM_COMMANDS_H_ #define _MTM_COMMANDS_H_ #include "mtm_structures.h" /* * Modified TPM commands */ /** * MTM_Extend - adds a new measurement to a PCR * @pcrNum: [in] The PCR to be updated * @inDigest: [in] The 160 bit value representing the event to be recorded * @outDigest: [out] The PCR value after execution of the command * Returns: TPM_SUCCESS on success, a TPM error code otherwise. */ TPM_RESULT MTM_Extend( TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, TPM_PCRVALUE *outDigest ); /** * MTM_PCR_Reset - resets the indicated PCRs * @pcrSelection: [in] The PCRs to reset * Returns: TPM_SUCCESS on success, a TPM error code otherwise. */ TPM_RESULT MTM_PCR_Reset( TPM_PCR_SELECTION *pcrSelection ); /** * MTM_GetCapability - provides current information regarding the TPM * @capArea: [in] Partition of capabilities to be interrogated * @subCapSize: [in] Size of subCap parameter * @subCap: [in] Further definition of information * @respSize: [out] The length of the returned capability response * @resp: [out] The capability response * Returns: TPM_SUCCESS on success, a TPM error code otherwise. */ TPM_RESULT MTM_GetCapability( TPM_CAPABILITY_AREA capArea, UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp ); /** * MTM_ReleaseCounter - releases a counter * @countID: [in] ID value of the counter * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. */ TPM_RESULT MTM_ReleaseCounter( TPM_COUNT_ID countID, TPM_AUTH *auth1 ); /** * MTM_ReleaseCounterOwner - releases a counter * @countID: [in] ID value of the counter * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. */ TPM_RESULT MTM_ReleaseCounterOwner( TPM_COUNT_ID countID, TPM_AUTH *auth1 ); /** * MTM_FlushSpecific - flushes a specific handle * @handle: [in] Handle of the item to flush * @resourceType: [in] The type of resource that is being flushed * Returns: TPM_SUCCESS on success, a TPM error code otherwise. */ TPM_RESULT MTM_FlushSpecific( TPM_HANDLE handle, TPM_RESOURCE_TYPE resourceType ); /* * Additional, MTM specific commands */ /** * MTM_InstallRIM - generates internal RIM certificates. * @rimCertIn: [in] Data to be used for internal RIM certificate * @auth1: [in, out] Authorization protocol parameters * @rimCertOut: [out] An internal RIM certificate * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([MTM_spec, v1.0], Section 7.2) */ TPM_RESULT MTM_InstallRIM( TPM_RIM_CERTIFICATE *rimCertIn, TPM_AUTH *auth1, TPM_RIM_CERTIFICATE *rimCertOut ); /** * MTM_LoadVerificationKey - load one Verification Key into the MTM * @parentKey: [in] Parent key used to verify this key * @auth1: [in, out] Authorization protocol parameters * @verificationKeyHandle: [out] Handle for the key that was loaded * @loadMethod: [out] which method was used to load this verification key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([MTM_spec, v1.0], Section 7.3) */ TPM_RESULT MTM_LoadVerificationKey( TPM_VERIFICATION_KEY_HANDLE parentKey, TPM_VERIFICATION_KEY *verificationKey, TPM_AUTH *auth1, TPM_VERIFICATION_KEY_HANDLE *verificationKeyHandle, BYTE *loadMethod ); /** * MTM_LoadVerificationRootKeyDisable - disables the functionality to load Verification Root Keys. * Returns: TPM_SUCCESS * * Description: ([MTM_spec, v1.0], Section 7.4) */ TPM_RESULT MTM_LoadVerificationRootKeyDisable(); /** * MTM_VerifyRIMCert - verify an internal or external RIM certificate. * @rimCert: [in] RIM certificate to be validated * @rimKey: [in] Key handle for the verification. NULL if internal verification key is used. * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([MTM_spec, v1.0], Section 7.5) */ TPM_RESULT MTM_VerifyRIMCert( TPM_RIM_CERTIFICATE* rimCert, TPM_VERIFICATION_KEY_HANDLE rimKey ); /** * MTM_VerifyRIMCertAndExtend - verify an internal or external RIM certificate and extend PCR given in RIM certificate. * @rimCert: [in] RIM certificate to be validated * @rimKey: [in] Key handle for the verification key. NULL if internal verification key is used. * @outDigest: [out] The PCR value after the execution of the command * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([MTM_spec, v1.0], Section 7.6) */ TPM_RESULT MTM_VerifyRIMCertAndExtend( TPM_RIM_CERTIFICATE *rimCert, TPM_VERIFICATION_KEY_HANDLE rimKey, TPM_PCRVALUE *outDigest ); /** * MTM_IncrementBootstrapCounter - increment bootstrap counter in MTM permanent data. * @rimCert: [in] A RIM certificate * @rimKey: [in] Key handle for the verification key to be used * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([MTM_spec, v1.0], Section 7.7) */ TPM_RESULT MTM_IncrementBootstrapCounter( TPM_RIM_CERTIFICATE *rimCert, TPM_VERIFICATION_KEY_HANDLE rimKey ); /** * MTM_SetVerifiedPCRSelection - Set verifiedPCRs field in MTM_PERMANENT_DATA * @verifiedSelection: [in] Set of PCRs that can only be extended with this function * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([MTM_spec, v1.0], Section 7.8) */ TPM_RESULT MTM_SetVerifiedPCRSelection( TPM_PCR_SELECTION *verifiedSelection, TPM_AUTH *auth1 ); TPM_RESULT mtm_execute_command(TPM_REQUEST *req, TPM_RESPONSE *rsp); #endif /* _MTM_COMMANDS_H_ */ ================================================ FILE: mtm/mtm_counter.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_commands.h" #include "tpm/tpm_handles.h" #include "tpm/tpm_commands.h" TPM_RESULT MTM_ReleaseCounter(TPM_COUNT_ID countID, TPM_AUTH *auth1) { int i = HANDLE_TO_INDEX(countID); info("MTM_ReleaseCounter()"); if (i == MTM_COUNTER_SELECT_BOOTSTRAP || i == MTM_COUNTER_SELECT_RIMPROTECT || i == MTM_COUNTER_SELECT_STORAGEPROTECT) { debug("MTM counters cannot be released"); return TPM_FAIL; } return TPM_ReleaseCounter(countID, auth1); } TPM_RESULT MTM_ReleaseCounterOwner(TPM_COUNT_ID countID, TPM_AUTH *auth1) { int i = HANDLE_TO_INDEX(countID); info("MTM_ReleaseCounterOwner()"); if (i == MTM_COUNTER_SELECT_BOOTSTRAP || i == MTM_COUNTER_SELECT_RIMPROTECT || i == MTM_COUNTER_SELECT_STORAGEPROTECT) { debug("MTM counters cannot be released"); return TPM_FAIL; } return TPM_ReleaseCounterOwner(countID, auth1); } ================================================ FILE: mtm/mtm_data.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_data.h" #include "tpm/tpm_data.h" MTM_DATA mtmData; static void set_counter(unsigned int num, const char *label) { TPM_COUNTER_VALUE *counter = &tpmData.permanent.data.counters[num]; counter->valid = TRUE; counter->tag = TPM_TAG_COUNTER_VALUE; memcpy(counter->label, label, sizeof(counter->label)); counter->counter = 1; memset(counter->usageAuth, 0, sizeof(TPM_SECRET)); } void mtm_init_data(void) { int i; info("initializing MTM data to default values"); /* reset all data to NULL, FALSE or 0 */ memset(&mtmData, 0, sizeof(mtmData)); mtmData.permanent.data.tag = MTM_TAG_PERMANENT_DATA; /* set specification version */ mtmData.permanent.data.specMajor = 0x01; mtmData.permanent.data.specMinor = 0x00; /* define verified PCRs */ mtmData.permanent.data.verifiedPCRs.sizeOfSelect = TPM_NUM_PCR / 8; for (i = 0; i < TPM_NUM_PCR / 8; i++) { mtmData.permanent.data.verifiedPCRs.pcrSelect[i] = 0x00; } /* map MTM counters to TPM counters */ set_counter(MTM_COUNTER_SELECT_BOOTSTRAP, "MTM1"); set_counter(MTM_COUNTER_SELECT_RIMPROTECT, "MTM2"); set_counter(MTM_COUNTER_SELECT_STORAGEPROTECT, "MTM3"); /* the field integrityCheckRootData is filled when the first verification key is loaded */ memset(mtmData.permanent.data.integrityCheckRootData, 0xff, sizeof(mtmData.permanent.data.integrityCheckRootData)); /* set internal verification key */ memcpy(mtmData.permanent.data.internalVerificationKey, "\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x77", sizeof(TPM_SECRET)); /* init flags */ mtmData.stany.flags.tag = MTM_TAG_STANY_FLAGS; mtmData.stany.flags.loadVerificationRootKeyEnabled = TRUE; } ================================================ FILE: mtm/mtm_data.h ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #ifndef _MTM_DATA_H_ #define _MTM_DATA_H_ #include "mtm_structures.h" extern MTM_DATA mtmData; void mtm_init_data(void); #endif /* _MTM_DATA_H_ */ ================================================ FILE: mtm/mtm_eviction.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_commands.h" #include "mtm_handles.h" #include "tpm/tpm_commands.h" TPM_RESULT MTM_FlushSpecific(TPM_HANDLE handle, TPM_RESOURCE_TYPE resourceType) { MTM_KEY_DATA *key; info("MTM_FlushSpecific()"); debug("handle = %08x, resourceType = %08x", handle, resourceType); if (resourceType == TPM_RT_KEY) { key = mtm_get_key(handle); if (key != NULL) { free_MTM_KEY_DATA((*key)); memset(key, 0, sizeof(*key)); tpm_invalidate_sessions(handle); return TPM_SUCCESS; } } return TPM_FlushSpecific(handle, resourceType); } ================================================ FILE: mtm/mtm_handles.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_handles.h" #include "mtm_data.h" MTM_KEY_DATA *mtm_get_key_slot(TPM_VERIFICATION_KEY_HANDLE handle) { if (handle == TPM_INVALID_HANDLE) return NULL; handle &= 0x00ffffff; if (handle < TPM_MAX_KEYS) return NULL; handle -= TPM_MAX_KEYS; if (handle >= MTM_MAX_KEYS) return NULL; return &mtmData.permanent.data.keys[handle]; } MTM_KEY_DATA *mtm_get_key(TPM_VERIFICATION_KEY_HANDLE handle) { if (handle == TPM_INVALID_HANDLE || (handle >> 24) != TPM_RT_KEY) return NULL; handle &= 0x00ffffff; if (handle < TPM_MAX_KEYS) return NULL; handle -= TPM_MAX_KEYS; if (handle >= MTM_MAX_KEYS || !mtmData.permanent.data.keys[handle].valid) return NULL; return &mtmData.permanent.data.keys[handle]; } MTM_KEY_DATA *mtm_get_key_by_id(TPM_VERIFICATION_KEY_ID id) { int i; for (i = 0; i < MTM_MAX_KEYS; i++) { if (mtmData.permanent.data.keys[i].valid && mtmData.permanent.data.keys[i].myId == id) return &mtmData.permanent.data.keys[i]; } return NULL; } ================================================ FILE: mtm/mtm_handles.h ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_structures.h" #include "tpm/tpm_handles.h" MTM_KEY_DATA *mtm_get_key_slot(TPM_VERIFICATION_KEY_HANDLE handle); MTM_KEY_DATA *mtm_get_key(TPM_VERIFICATION_KEY_HANDLE handle); MTM_KEY_DATA *mtm_get_key_by_id(TPM_VERIFICATION_KEY_ID id); ================================================ FILE: mtm/mtm_integrity.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_structures.h" #include "mtm_data.h" #include "tpm/tpm_commands.h" TPM_RESULT MTM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, TPM_PCRVALUE *outDigest) { info("MTM_Extend()"); if (mtmData.permanent.data.verifiedPCRs.pcrSelect[pcrNum >> 3] & (1 << (pcrNum & 7))) { return TPM_BAD_LOCALITY; } return TPM_Extend(pcrNum, inDigest, outDigest); } TPM_RESULT MTM_PCR_Reset(TPM_PCR_SELECTION *pcrSelection) { int i; info("MTM_PCR_Reset()"); for (i = 0; i < pcrSelection->sizeOfSelect * 8; i++) { if ((pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) && (mtmData.permanent.data.verifiedPCRs.pcrSelect[i >> 3] & (1 << (i & 7)))) { return TPM_FAIL; } } return TPM_PCR_Reset(pcrSelection); } ================================================ FILE: mtm/mtm_marshalling.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #include "mtm_marshalling.h" int tpm_marshal_MTM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, MTM_PERMANENT_DATA *v) { int i; if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BYTE(ptr, length, v->specMajor) || tpm_marshal_BYTE(ptr, length, v->specMinor) || tpm_marshal_TPM_PCR_SELECTION(ptr, length, &v->verifiedPCRs) || tpm_marshal_TPM_COUNT_ID(ptr, length, v->counterRimProtectId) || tpm_marshal_TPM_COUNT_ID(ptr, length, v->counterStorageProtectId) || tpm_marshal_BYTE(ptr, length, v->loadVerificationKeyMethods) || tpm_marshal_BOOL(ptr, length, v->integrityCheckRootValid) || tpm_marshal_BYTE_ARRAY(ptr, length, v->integrityCheckRootData, sizeof(v->integrityCheckRootData)) || tpm_marshal_TPM_SECRET(ptr, length, &v->internalVerificationKey)) return -1; for (i = 0; i < MTM_MAX_KEYS; i++) { if (tpm_marshal_MTM_KEY_DATA(ptr, length, &v->keys[i])) return -1; } return 0; } int tpm_unmarshal_MTM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, MTM_PERMANENT_DATA *v) { int i; if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BYTE(ptr, length, &v->specMajor) || tpm_unmarshal_BYTE(ptr, length, &v->specMinor) || tpm_unmarshal_TPM_PCR_SELECTION(ptr, length, &v->verifiedPCRs) || tpm_unmarshal_TPM_COUNT_ID(ptr, length, &v->counterRimProtectId) || tpm_unmarshal_TPM_COUNT_ID(ptr, length, &v->counterStorageProtectId) || tpm_unmarshal_BYTE(ptr, length, &v->loadVerificationKeyMethods) || tpm_unmarshal_BOOL(ptr, length, &v->integrityCheckRootValid) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->integrityCheckRootData, sizeof(v->integrityCheckRootData)) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->internalVerificationKey)) return -1; for (i = 0; i < MTM_MAX_KEYS; i++) { if (tpm_unmarshal_MTM_KEY_DATA(ptr, length, &v->keys[i])) return -1; } return 0; } int tpm_marshal_MTM_STANY_FLAGS(BYTE **ptr, UINT32 *length, MTM_STANY_FLAGS *v) { if (tpm_marshal_TPM_TAG(ptr, length, v->tag) || tpm_marshal_BOOL(ptr, length, v->loadVerificationRootKeyEnabled)) return -1; return 0; } int tpm_unmarshal_MTM_STANY_FLAGS(BYTE **ptr, UINT32 *length, MTM_STANY_FLAGS *v) { if (tpm_unmarshal_TPM_TAG(ptr, length, &v->tag) || tpm_unmarshal_BOOL(ptr, length, &v->loadVerificationRootKeyEnabled)) return -1; return 0; } int tpm_marshal_MTM_COUNTER_REFERENCE(BYTE **ptr, UINT32 *length, MTM_COUNTER_REFERENCE *v) { if (tpm_marshal_BYTE(ptr, length, v->counterSelection) || tpm_marshal_TPM_ACTUAL_COUNT(ptr, length, v->counterValue)) return -1; return 0; } int tpm_unmarshal_MTM_COUNTER_REFERENCE(BYTE **ptr, UINT32 *length, MTM_COUNTER_REFERENCE *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->counterSelection) || tpm_unmarshal_TPM_ACTUAL_COUNT(ptr, length, &v->counterValue)) return -1; return 0; } int tpm_marshal_TPM_RIM_CERTIFICATE(BYTE **ptr, UINT32 *length, TPM_RIM_CERTIFICATE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BYTE_ARRAY(ptr, length, v->label, 8) || tpm_marshal_UINT32(ptr, length, v->rimVersion) || tpm_marshal_MTM_COUNTER_REFERENCE(ptr, length, &v->referenceCounter) || tpm_marshal_TPM_PCR_INFO_SHORT(ptr, length, &v->state) || tpm_marshal_UINT32(ptr, length, v->measurementPcrIndex) || tpm_marshal_TPM_PCRVALUE(ptr, length, &v->measurementValue) || tpm_marshal_TPM_VERIFICATION_KEY_ID(ptr, length, v->parentId) || tpm_marshal_BYTE(ptr, length, v->extensionDigestSize) || (v->extensionDigestSize > 0 && tpm_marshal_BLOB(ptr, length, v->extensionDigestData, v->extensionDigestSize)) || tpm_marshal_UINT32(ptr, length, v->integrityCheckSize) || (v->integrityCheckSize > 0 && tpm_marshal_BLOB(ptr, length, v->integrityCheckData, v->integrityCheckSize))) return -1; return 0; } int tpm_unmarshal_TPM_RIM_CERTIFICATE(BYTE **ptr, UINT32 *length, TPM_RIM_CERTIFICATE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->label, 8) || tpm_unmarshal_UINT32(ptr, length, &v->rimVersion) || tpm_unmarshal_MTM_COUNTER_REFERENCE(ptr, length, &v->referenceCounter) || tpm_unmarshal_TPM_PCR_INFO_SHORT(ptr, length, &v->state) || tpm_unmarshal_UINT32(ptr, length, &v->measurementPcrIndex) || tpm_unmarshal_TPM_PCRVALUE(ptr, length, &v->measurementValue) || tpm_unmarshal_TPM_VERIFICATION_KEY_ID(ptr, length, &v->parentId) || tpm_unmarshal_BYTE(ptr, length, &v->extensionDigestSize) || (v->extensionDigestSize > 0 && tpm_unmarshal_BLOB(ptr, length, &v->extensionDigestData, v->extensionDigestSize)) || tpm_unmarshal_UINT32(ptr, length, &v->integrityCheckSize) || (v->integrityCheckSize > 0 && tpm_unmarshal_BLOB(ptr, length, &v->integrityCheckData, v->integrityCheckSize))) return -1; return 0; } int tpm_marshal_TPM_VERIFICATION_KEY(BYTE **ptr, UINT32 *length, TPM_VERIFICATION_KEY *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_UINT16(ptr, length, v->usageFlags) || tpm_marshal_TPM_VERIFICATION_KEY_ID(ptr, length, v->parentId) || tpm_marshal_TPM_VERIFICATION_KEY_ID(ptr, length, v->myId) || tpm_marshal_MTM_COUNTER_REFERENCE(ptr, length, &v->referenceCounter) || tpm_marshal_TPM_ALGORITHM_ID(ptr, length, v->keyAlgorithm) || tpm_marshal_TPM_SIG_SCHEME(ptr, length, v->keyScheme) || tpm_marshal_BYTE(ptr, length, v->extensionDigestSize) || (v->extensionDigestSize > 0 && tpm_marshal_BLOB(ptr, length, v->extensionDigestData, v->extensionDigestSize)) || tpm_marshal_UINT32(ptr, length, v->keySize) || (v->keySize > 0 && tpm_marshal_BLOB(ptr, length, v->keyData, v->keySize)) || tpm_marshal_UINT32(ptr, length, v->integrityCheckSize) || (v->integrityCheckSize > 0 && tpm_marshal_BLOB(ptr, length, v->integrityCheckData, v->integrityCheckSize))) return -1; return 0; } int tpm_unmarshal_TPM_VERIFICATION_KEY(BYTE **ptr, UINT32 *length, TPM_VERIFICATION_KEY *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT16(ptr, length, &v->usageFlags) || tpm_unmarshal_TPM_VERIFICATION_KEY_ID(ptr, length, &v->parentId) || tpm_unmarshal_TPM_VERIFICATION_KEY_ID(ptr, length, &v->myId) || tpm_unmarshal_MTM_COUNTER_REFERENCE(ptr, length, &v->referenceCounter) || tpm_unmarshal_TPM_ALGORITHM_ID(ptr, length, &v->keyAlgorithm) || tpm_unmarshal_TPM_SIG_SCHEME(ptr, length, &v->keyScheme) || tpm_unmarshal_BYTE(ptr, length, &v->extensionDigestSize) || (v->extensionDigestSize > 0 && tpm_unmarshal_BLOB(ptr, length, &v->extensionDigestData, v->extensionDigestSize)) || tpm_unmarshal_UINT32(ptr, length, &v->keySize) || (v->keySize > 0 && tpm_unmarshal_BLOB(ptr, length, &v->keyData, v->keySize)) || tpm_unmarshal_UINT32(ptr, length, &v->integrityCheckSize) || (v->integrityCheckSize > 0 && tpm_unmarshal_BLOB(ptr, length, &v->integrityCheckData, v->integrityCheckSize))) return -1; return 0; } int tpm_marshal_MTM_KEY_DATA(BYTE **ptr, UINT32 *length, MTM_KEY_DATA *v) { if (tpm_marshal_BOOL(ptr, length, v->valid)) return -1; if (v->valid) { if (tpm_marshal_UINT16(ptr, length, v->usageFlags) || tpm_marshal_TPM_VERIFICATION_KEY_ID(ptr, length, v->parentId) || tpm_marshal_TPM_VERIFICATION_KEY_ID(ptr, length, v->myId) || tpm_marshal_TPM_ALGORITHM_ID(ptr, length, v->keyAlgorithm) || tpm_marshal_TPM_SIG_SCHEME(ptr, length, v->keyScheme) || tpm_marshal_RSAPub(ptr, length, &v->key)) return -1; } return 0; } int tpm_unmarshal_MTM_KEY_DATA(BYTE **ptr, UINT32 *length, MTM_KEY_DATA *v) { if (tpm_unmarshal_BOOL(ptr, length, &v->valid)) return -1; if (v->valid) { if (tpm_unmarshal_UINT16(ptr, length, &v->usageFlags) || tpm_unmarshal_TPM_VERIFICATION_KEY_ID(ptr, length, &v->parentId) || tpm_unmarshal_TPM_VERIFICATION_KEY_ID(ptr, length, &v->myId) || tpm_unmarshal_TPM_ALGORITHM_ID(ptr, length, &v->keyAlgorithm) || tpm_unmarshal_TPM_SIG_SCHEME(ptr, length, &v->keyScheme) || tpm_unmarshal_RSAPub(ptr, length, &v->key)) return -1; } return 0; } int tpm_marshal_MTM_DATA(BYTE **ptr, UINT32 *length, MTM_DATA *v) { if (tpm_marshal_MTM_PERMANENT_DATA(ptr, length, &v->permanent.data) || tpm_marshal_MTM_STANY_FLAGS(ptr, length, &v->stany.flags)) return -1; return 0; } int tpm_unmarshal_MTM_DATA(BYTE **ptr, UINT32 *length, MTM_DATA *v) { if (tpm_unmarshal_MTM_PERMANENT_DATA(ptr, length, &v->permanent.data) || tpm_unmarshal_MTM_STANY_FLAGS(ptr, length, &v->stany.flags)) return -1; return 0; } ================================================ FILE: mtm/mtm_marshalling.h ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #ifndef _MTM_MARSHALLING_H_ #define _MTM_MARSHALLING_H_ #include "mtm_structures.h" #include "tpm/tpm_marshalling.h" #define tpm_marshal_TPM_VERIFICATION_KEY_ID tpm_marshal_UINT32 #define tpm_unmarshal_TPM_VERIFICATION_KEY_ID tpm_unmarshal_UINT32 #define tpm_marshal_TPM_VERIFICATION_KEY_HANDLE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_VERIFICATION_KEY_HANDLE tpm_unmarshal_UINT32 int tpm_marshal_MTM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, MTM_PERMANENT_DATA *v); int tpm_unmarshal_MTM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, MTM_PERMANENT_DATA *v); int tpm_marshal_MTM_STANY_FLAGS(BYTE **ptr, UINT32 *length, MTM_STANY_FLAGS *v); int tpm_unmarshal_MTM_STANY_FLAGS(BYTE **ptr, UINT32 *length, MTM_STANY_FLAGS *v); int tpm_marshal_MTM_COUNTER_REFERENCE(BYTE **ptr, UINT32 *length, MTM_COUNTER_REFERENCE *v); int tpm_unmarshal_MTM_COUNTER_REFERENCE(BYTE **ptr, UINT32 *length, MTM_COUNTER_REFERENCE *v); int tpm_marshal_TPM_RIM_CERTIFICATE(BYTE **ptr, UINT32 *length, TPM_RIM_CERTIFICATE *v); int tpm_unmarshal_TPM_RIM_CERTIFICATE(BYTE **ptr, UINT32 *length, TPM_RIM_CERTIFICATE *v); int tpm_marshal_TPM_VERIFICATION_KEY(BYTE **ptr, UINT32 *length, TPM_VERIFICATION_KEY *v); int tpm_unmarshal_TPM_VERIFICATION_KEY(BYTE **ptr, UINT32 *length, TPM_VERIFICATION_KEY *v); int tpm_marshal_MTM_KEY_DATA(BYTE **ptr, UINT32 *length, MTM_KEY_DATA *v); int tpm_unmarshal_MTM_KEY_DATA(BYTE **ptr, UINT32 *length, MTM_KEY_DATA *v); int tpm_marshal_MTM_DATA(BYTE **ptr, UINT32 *length, MTM_DATA *v); int tpm_unmarshal_MTM_DATA(BYTE **ptr, UINT32 *length, MTM_DATA *v); #endif /* _MTM_MARSHALLING_H_ */ ================================================ FILE: mtm/mtm_structures.h ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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$ */ #ifndef _MTM_STRUCTURES_H_ #define _MTM_STRUCTURES_H_ #include "tpm/tpm_structures.h" #include "crypto/sha1.h" /* * Ordinals * The command ordinals provide the index value for each command. */ #define MTM_ORD_InstallRIM (66 + TPM_PROTECTED_COMMAND) #define MTM_ORD_LoadVerificationKey (67 + TPM_PROTECTED_COMMAND) #define MTM_ORD_LoadVerificationRootKeyDisable (68 + TPM_PROTECTED_COMMAND) #define MTM_ORD_VerifyRIMCert (69 + TPM_PROTECTED_COMMAND) #define MTM_ORD_VerifyRIMCertAndExtend (72 + TPM_PROTECTED_COMMAND) #define MTM_ORD_IncrementBootstrapCounter (73 + TPM_PROTECTED_COMMAND) #define MTM_ORD_SetVerifiedPCRSelection (74 + TPM_PROTECTED_COMMAND) /* * TPM_CAPABILITY_AREA Values for TPM_GetCapability */ #define TPM_CAP_MTM_PERMANENT_DATA 0x0000000A /* * MTM_COUNTER_REFERENCE ([MTM], Section 5.1) * MTM counter reference structure */ #define MTM_COUNTER_SELECT_NONE 0 #define MTM_COUNTER_SELECT_BOOTSTRAP 1 #define MTM_COUNTER_SELECT_RIMPROTECT 2 #define MTM_COUNTER_SELECT_STORAGEPROTECT 3 #define MTM_COUNTER_SELECT_MAX 3 typedef struct MTM_COUNTER_REFERENCE_STRUCT { BYTE counterSelection; TPM_ACTUAL_COUNT counterValue; } MTM_COUNTER_REFERENCE; #define sizeof_MTM_COUNTER_REFERENCE(s) (1 + 4) /* * TPM_VERIFICATION_KEY_ID ([MTM], Section 5.3) */ typedef UINT32 TPM_VERIFICATION_KEY_ID; #define TPM_VERIFICATION_KEY_ID_NONE 0xFFFFFFFF #define TPM_VERIFICATION_KEY_ID_INTERNAL 0xFFFFFFFE /* * TPM_VERIFICATION_KEY_USAGE ([MTM], Section 5.3) */ #define TPM_VERIFICATION_KEY_USAGE_MTM_MASK 0x00ff #define TPM_VERIFICATION_KEY_USAGE_AGENT_MASK 0x0f00 #define TPM_VERIFICATION_KEY_USAGE_VENDOR_MASK 0xf000 #define TPM_VERIFICATION_KEY_USAGE_SIGN_RIMCERT 0x0001 #define TPM_VERIFICATION_KEY_USAGE_SIGN_RIMAUTH 0x0002 #define TPM_VERIFICATION_KEY_USAGE_INCREMENT_BOOTSTRAP 0x0004 /* * TPM_VERIFICATION_KEY_HANDLE ([MTM], Section 5.3) * Handle used to refer to TPM_VERIFICATION_KEY structures */ typedef UINT32 TPM_VERIFICATION_KEY_HANDLE; /* * TPM_VERIFICATION_KEY ([MTM], Section 5.3) * The TPM_VERIFICATION_KEY structure is used for representing keys in * the authorization hierarchy used to authorize RIM_Certs for a MTM. */ #define TPM_TAG_VERIFICATION_KEY 0x0301 typedef struct TPM_VERIFICATION_KEY_STRUCT { TPM_STRUCTURE_TAG tag; UINT16 usageFlags; TPM_VERIFICATION_KEY_ID parentId; TPM_VERIFICATION_KEY_ID myId; MTM_COUNTER_REFERENCE referenceCounter; TPM_ALGORITHM_ID keyAlgorithm; TPM_SIG_SCHEME keyScheme; BYTE extensionDigestSize; BYTE* extensionDigestData; UINT32 keySize; BYTE* keyData; UINT32 integrityCheckSize; BYTE* integrityCheckData; } TPM_VERIFICATION_KEY; #define sizeof_TPM_VERIFICATION_KEY(s) (2 + 2 + 4 + 4 \ + sizeof_MTM_COUNTER_REFERENCE(s.referenceCounter) + 4 + 2 + 1 \ + s.extensionDigestSize + 4 + s.keySize + 4 + s.integrityCheckSize) #define free_TPM_VERIFICATION_KEY(s) { \ if (s.extensionDigestSize > 0) tpm_free(s.extensionDigestData); \ if (s.keySize > 0) tpm_free(s.keyData); \ if (s.integrityCheckSize > 0) tpm_free(s.integrityCheckData); } /* * TPM_RIM_CERTIFICATE ([MTM], Section 5.2) * A RIM Certificate is a structure authorizing a measurement value * that is extended using MTM_VerifyRIMCertAndExtend into a PCR * defined in the RIM Certificate. */ #define TPM_TAG_RIM_CERTIFICATE 0x0302 typedef struct TPM_RIM_CERTIFICATE_STRUCT { TPM_STRUCTURE_TAG tag; BYTE label[8]; UINT32 rimVersion; MTM_COUNTER_REFERENCE referenceCounter; TPM_PCR_INFO_SHORT state; UINT32 measurementPcrIndex; TPM_PCRVALUE measurementValue; TPM_VERIFICATION_KEY_ID parentId; BYTE extensionDigestSize; BYTE *extensionDigestData; UINT32 integrityCheckSize; BYTE *integrityCheckData; } TPM_RIM_CERTIFICATE; #define sizeof_TPM_RIM_CERTIFICATE(s) (2 + 8 + 4 \ + sizeof_MTM_COUNTER_REFERENCE(s.referenceCounter) \ + sizeof_TPM_PCR_INFO_SHORT(s.state) \ + 4 + 20 + 4 + 1 + s.extensionDigestSize \ + 4 + s.integrityCheckSize) #define free_TPM_RIM_CERTIFICATE(s) { \ if (s.extensionDigestSize > 0) tpm_free(s.extensionDigestData); \ if (s.integrityCheckSize > 0) tpm_free(s.integrityCheckData); } /* * TPM_VERIFICATION_KEY_LOAD_METHODS ([MTM], Section 5.4) * Methods to load a TPM_VERIFICATION_KEY */ typedef BYTE TPM_VERIFICATION_KEY_LOAD_METHODS; #define TPM_VERIFICATION_KEY_ROOT_LOAD 0x01 #define TPM_VERIFICATION_KEY_INTEGRITY_CHECK_ROOT_DATA_LOAD 0x02 #define TPM_VERIFICATION_KEY_OWNER_AUTHORIZED_LOAD 0x04 #define TPM_VERIFICATION_KEY_CHAIN_AUTHORIZED_LOAD 0x08 /* * MTM_KEY_DATA * This structure contains the data for stored MTM verification keys. */ typedef struct MTM_KEY_DATA_STRUCT { BOOL valid; UINT16 usageFlags; TPM_VERIFICATION_KEY_ID parentId; TPM_VERIFICATION_KEY_ID myId; TPM_ALGORITHM_ID keyAlgorithm; TPM_SIG_SCHEME keyScheme; tpm_rsa_public_key_t key; } MTM_KEY_DATA; #define sizeof_MTM_KEY_DATA(s) ( \ 1 + 2 + 4 + 4 + 4 + 2 + sizeof_RSAPub(s.key)) #define free_MTM_KEY_DATA(s) { tpm_rsa_release_public_key(&s.key); } /* * MTM_PERMANENT_DATA ([MTM], Section 5.4) * The MTM_PERMANENT_DATA structure contains the permanent data associated * with a MTM that are used by the MTM commands. Note that there is an * alternative where there is only AIK but no EK defined. */ #define MTM_TAG_PERMANENT_DATA 0x0303 #define MTM_MAX_KEYS 10 typedef struct MTM_PERMANENT_DATA_STRUCT { TPM_STRUCTURE_TAG tag; BYTE specMajor; BYTE specMinor; /* TPM_KEY aik; - not needed as the EK is always present */ TPM_PCR_SELECTION verifiedPCRs; TPM_COUNT_ID counterRimProtectId; TPM_COUNT_ID counterStorageProtectId; TPM_VERIFICATION_KEY_LOAD_METHODS loadVerificationKeyMethods; BOOL integrityCheckRootValid; BYTE integrityCheckRootData[SHA1_DIGEST_LENGTH]; TPM_SECRET internalVerificationKey; /* TPM_SECRET verificationAuth; - is a mirror of the ownerAuth */ MTM_KEY_DATA keys[MTM_MAX_KEYS]; } MTM_PERMANENT_DATA; static inline int sizeof_MTM_PERMANENT_DATA(MTM_PERMANENT_DATA *s) { int i, size = 2 + 1 + 1 + 4 + 4 + 1 + 1 + 20; size += sizeof_TPM_PCR_SELECTION(s->verifiedPCRs); size += sizeof(s->integrityCheckRootData); for (i = 0; i < MTM_MAX_KEYS; i++) { if (s->keys[i].valid) { size += sizeof_MTM_KEY_DATA(s->keys[i]); } else { size += 1; } } return size; } static inline void free_MTM_PERMANENT_DATA(MTM_PERMANENT_DATA *s) { int i; for (i = 0; i < MTM_MAX_KEYS; i++) { if (s->keys[i].valid) free_MTM_KEY_DATA(s->keys[i]); } } /* * The MTM_STANY_FLAGS structure houses additional flags that are * initialized by TPM_Init when the MTM boots. */ #define MTM_TAG_STANY_FLAGS 0x0304 typedef struct MTM_STANY_FLAGS_STRUCT { TPM_TAG tag; BOOL loadVerificationRootKeyEnabled; } MTM_STANY_FLAGS; #define sizeof_MTM_STANY_FLAGS(s) (2 + 1) /* * MTM_DATA * Internal data of the MTM */ typedef struct tdMTM_DATA { struct { MTM_PERMANENT_DATA data; } permanent; // struct { // } stclear; struct { MTM_STANY_FLAGS flags; } stany; } MTM_DATA; #define sizeof_MTM_DATA(s) (sizeof_MTM_PERMANENT_DATA(&s.permanent.data) \ + sizeof_MTM_STANY_FLAGS(s.stany.flags)) #define free_MTM_DATA(s) { free_MTM_PERMANENT_DATA(&s.permanent.data); } #endif /* _MTM_STRUCTURES_H */ ================================================ FILE: mtm/mtm_verification.c ================================================ /* Software-based Mobile Trusted Module (MTM) Emulator * Copyright (C) 2004-2010 Mario Strasser * Copyright (C) 2007 Jan-Erik Ekberg , * Nokia Corporation and/or its subsidiary(-ies) * * 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$ */ #include "mtm_structures.h" #include "mtm_commands.h" #include "tpm/tpm_commands.h" #include "mtm_data.h" #include "tpm/tpm_data.h" #include "mtm_handles.h" #include "mtm_marshalling.h" #include "crypto/hmac.h" #include "crypto/rsa.h" #include "crypto/sha1.h" static int copy_TPM_RIM_CERTIFICATE(TPM_RIM_CERTIFICATE* src, TPM_RIM_CERTIFICATE* dst) { memcpy(dst, src, sizeof(TPM_RIM_CERTIFICATE)); if (dst->extensionDigestSize > 0) { dst->extensionDigestData = tpm_malloc(dst->extensionDigestSize); if (dst->extensionDigestData == NULL) return -1; memcpy(dst->extensionDigestData, src->extensionDigestData, dst->extensionDigestSize); } else { dst->extensionDigestData = NULL; } if (dst->integrityCheckSize > 0) { dst->integrityCheckData = tpm_malloc(dst->integrityCheckSize); if (dst->integrityCheckData == NULL) { tpm_free(dst->extensionDigestData); return -1; } memcpy(dst->integrityCheckData, src->integrityCheckData, dst->integrityCheckSize); } else { dst->integrityCheckData = NULL; } return 0; } static int compute_rim_certificate_digest(TPM_RIM_CERTIFICATE* rimCert, BYTE *digest) { tpm_sha1_ctx_t sha1_ctx; BYTE *buf, *ptr; UINT32 buf_len, len; UINT32 integrityCheckSize; /* marshal certificate */ integrityCheckSize = rimCert->integrityCheckSize; rimCert->integrityCheckSize = 0; buf_len = len = sizeof_TPM_RIM_CERTIFICATE((*rimCert)); buf = ptr = tpm_malloc(buf_len); if (buf == NULL || tpm_marshal_TPM_RIM_CERTIFICATE(&ptr, &len, rimCert)) { rimCert->integrityCheckSize = integrityCheckSize; tpm_free(buf); return -1; } rimCert->integrityCheckSize = integrityCheckSize; /* compute hmac */ tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, buf_len); tpm_sha1_final(&sha1_ctx, digest); tpm_free(buf); return 0; } static int compute_rim_certificate_hmac(TPM_RIM_CERTIFICATE* rimCert, BYTE *digest) { tpm_hmac_ctx_t hmac_ctx; BYTE *buf, *ptr; UINT32 buf_len, len; UINT32 integrityCheckSize; /* marshal certificate */ integrityCheckSize = rimCert->integrityCheckSize; rimCert->integrityCheckSize = 0; buf_len = len = sizeof_TPM_RIM_CERTIFICATE((*rimCert)); buf = ptr = tpm_malloc(buf_len); if (buf == NULL || tpm_marshal_TPM_RIM_CERTIFICATE(&ptr, &len, rimCert)) { rimCert->integrityCheckSize = integrityCheckSize; tpm_free(buf); return -1; } rimCert->integrityCheckSize = integrityCheckSize; /* compute hmac */ tpm_hmac_init(&hmac_ctx, mtmData.permanent.data.internalVerificationKey, sizeof(TPM_SECRET)); tpm_hmac_update(&hmac_ctx, buf, buf_len); tpm_hmac_final(&hmac_ctx, digest); tpm_free(buf); return 0; } static TPM_RESULT verify_rim_certificate(TPM_RIM_CERTIFICATE *rimCert) { /* check parrentID */ debug("parentId = %08x", rimCert->parentId); if (rimCert->parentId == TPM_VERIFICATION_KEY_ID_NONE) return TPM_KEYNOTFOUND; /* verify certificate with appropiate key */ if (rimCert->parentId == TPM_VERIFICATION_KEY_ID_INTERNAL) { BYTE digest[SHA1_DIGEST_LENGTH]; debug("internal verification"); if (compute_rim_certificate_hmac(rimCert, digest) != 0) { debug("compute_rim_certificate_hmac() failed"); return TPM_FAIL; } /* check hmac */ if (memcmp(digest, rimCert->integrityCheckData, SHA1_DIGEST_LENGTH) != 0) { debug("verification failed"); return TPM_AUTHFAIL; } else { debug("verification succeeded"); return TPM_SUCCESS; } } else { BYTE digest[SHA1_DIGEST_LENGTH]; /* get verification key */ MTM_KEY_DATA *key = mtm_get_key_by_id(rimCert->parentId); if (key == NULL) { return TPM_KEYNOTFOUND; } /* compute digest */ if (compute_rim_certificate_digest(rimCert, digest) != 0) { debug("compute_rim_certificate_digest() failed"); return TPM_FAIL; } /* check key properties */ if (key->keyAlgorithm != TPM_ALG_RSA || key->keyScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { debug("invalid signature scheme"); return TPM_BAD_SCHEME; } /* verify signature */ if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1_RAW, digest, sizeof(digest), rimCert->integrityCheckData) != 0) { debug("verification failed"); return TPM_AUTHFAIL; } else { debug("verification succeeded"); return TPM_SUCCESS; } } } static int compute_verification_key_digest(TPM_VERIFICATION_KEY *key, BYTE *digest) { tpm_sha1_ctx_t sha1_ctx; BYTE *buf, *ptr; UINT32 buf_len, len; UINT32 integrityCheckSize; /* marshal certificate */ integrityCheckSize = key->integrityCheckSize; key->integrityCheckSize = 0; buf_len = len = sizeof_TPM_VERIFICATION_KEY((*key)); buf = ptr = tpm_malloc(buf_len); if (buf == NULL || tpm_marshal_TPM_VERIFICATION_KEY(&ptr, &len, key)) { key->integrityCheckSize = integrityCheckSize; tpm_free(buf); return -1; } key->integrityCheckSize = integrityCheckSize; /* compute sha1 */ tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, buf_len); tpm_sha1_final(&sha1_ctx, digest); tpm_free(buf); return 0; } static TPM_RESULT verify_verification_key(TPM_VERIFICATION_KEY *key, MTM_KEY_DATA *parentKey) { BYTE digest[SHA1_DIGEST_LENGTH]; /* compute digest */ if (compute_verification_key_digest(key, digest) != 0) { debug("compute_verification_key_digest() failed"); return TPM_FAIL; } /* check key properties */ if (parentKey->keyAlgorithm != TPM_ALG_RSA || parentKey->keyScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { debug("invalid signature scheme"); return TPM_BAD_SCHEME; } /* verify signature */ if (tpm_rsa_verify(&parentKey->key, RSA_SSA_PKCS1_SHA1_RAW, digest, sizeof(digest), key->integrityCheckData) != 0) { debug("verification failed"); return TPM_AUTHFAIL; } else { debug("verification succeeded"); return TPM_SUCCESS; } } static int store_verification_key(TPM_VERIFICATION_KEY *inKey, MTM_KEY_DATA *outKey) { outKey->usageFlags = inKey->usageFlags; outKey->parentId = inKey->parentId; outKey->myId = inKey->myId; outKey->keyAlgorithm = inKey->keyAlgorithm; outKey->keyScheme = inKey->keyScheme; BYTE *ptr = inKey->keyData; UINT32 len = inKey->keySize; if (tpm_unmarshal_RSAPub(&ptr, &len, &outKey->key) != 0) return -1; return 0; } TPM_RESULT MTM_InstallRIM(TPM_RIM_CERTIFICATE *rimCertIn, TPM_AUTH *auth1, TPM_RIM_CERTIFICATE *rimCertOut) { TPM_RESULT res; TPM_ACTUAL_COUNT cntProtect; info("MTM_InstallRIM()"); /* 1 */ if (rimCertIn == NULL || rimCertIn->tag != TPM_TAG_RIM_CERTIFICATE) return TPM_BAD_PARAMETER; /* 2 */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, auth1->authHandle); if (res != TPM_SUCCESS) return res; /* 3 */ cntProtect = tpmData.permanent.data.counters[MTM_COUNTER_SELECT_RIMPROTECT].counter; /* 5 */ rimCertIn->integrityCheckSize = SHA1_DIGEST_LENGTH; if (copy_TPM_RIM_CERTIFICATE(rimCertIn, rimCertOut) != 0) { debug("copy_TPM_RIM_CERTIFICATE() failed"); return TPM_FAIL; } /* 6, 7 */ if (rimCertIn->referenceCounter.counterSelection != MTM_COUNTER_SELECT_NONE) { rimCertOut->referenceCounter.counterValue = cntProtect + 1; rimCertOut->referenceCounter.counterSelection = MTM_COUNTER_SELECT_RIMPROTECT; } else { rimCertOut->referenceCounter.counterValue = 0; } /* 8 */ rimCertOut->parentId = TPM_VERIFICATION_KEY_ID_INTERNAL; /* 10, 11, 12 */ if (compute_rim_certificate_hmac(rimCertOut, rimCertOut->integrityCheckData) != 0) { debug("compute_rim_certificate_hmac() failed"); free_TPM_RIM_CERTIFICATE((*rimCertOut)); return TPM_FAIL; } /* 13 */ return TPM_SUCCESS; } static TPM_VERIFICATION_KEY_HANDLE mtm_get_free_key(void) { int i; for (i = 0; i < TPM_MAX_KEYS; i++) { if (!mtmData.permanent.data.keys[i].valid) { mtmData.permanent.data.keys[i].valid = TRUE; return INDEX_TO_KEY_HANDLE(i); } } return TPM_INVALID_HANDLE; } TPM_RESULT MTM_LoadVerificationKey(TPM_VERIFICATION_KEY_HANDLE parentKeyHandle, TPM_VERIFICATION_KEY *verificationKey, TPM_AUTH *auth1, TPM_VERIFICATION_KEY_HANDLE *verificationKeyHandle, BYTE *loadMethod) { TPM_RESULT res; MTM_KEY_DATA *key; /* 1 */ if (verificationKey == NULL || verificationKey->tag != TPM_TAG_VERIFICATION_KEY) return TPM_BAD_PARAMETER; /* 2 */ *verificationKeyHandle = mtm_get_free_key(); key = mtm_get_key(*verificationKeyHandle); if (key == NULL) { debug("no free key slot available"); return TPM_NOSPACE; } *loadMethod = 0; /* 3 */ if (mtmData.stany.flags.loadVerificationRootKeyEnabled) { debug("TPM_VERIFICATION_KEY_ROOT_LOAD"); /* set integrityCheckRootData */ if (!mtmData.permanent.data.integrityCheckRootValid) { if (compute_verification_key_digest(verificationKey, mtmData.permanent.data.integrityCheckRootData) != 0) { debug("compute_verification_key_digest() failed"); memset(key, 0, sizeof(*key)); return TPM_FAIL; } mtmData.permanent.data.integrityCheckRootValid = TRUE; } *loadMethod = TPM_VERIFICATION_KEY_ROOT_LOAD; } /* 4 */ if (*loadMethod == 0 && mtmData.permanent.data.integrityCheckRootValid) { BYTE digest[SHA1_DIGEST_LENGTH]; if (compute_verification_key_digest(verificationKey, digest) != 0) { debug("compute_verification_key_digest() failed"); memset(key, 0, sizeof(*key)); return TPM_FAIL; } if (memcmp(mtmData.permanent.data.integrityCheckRootData, digest, SHA1_DIGEST_LENGTH) == 0) { debug("TPM_VERIFICATION_KEY_INTEGRITY_CHECK_ROOT_DATA_LOAD"); *loadMethod = TPM_VERIFICATION_KEY_INTEGRITY_CHECK_ROOT_DATA_LOAD; } } /* 5 */ if (*loadMethod == 0 && tpmData.permanent.flags.owned && auth1->authHandle != TPM_INVALID_HANDLE) { TPM_RESULT res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) { memset(key, 0, sizeof(*key)); return res; } debug("TPM_VERIFICATION_KEY_OWNER_AUTHORIZED_LOAD"); *loadMethod = TPM_VERIFICATION_KEY_OWNER_AUTHORIZED_LOAD; } /* 6 */ if (*loadMethod == 0) { MTM_KEY_DATA *parentKey = mtm_get_key(parentKeyHandle); if (parentKey == NULL) { debug("invalid parent key handle %08x", parentKeyHandle); memset(key, 0, sizeof(*key)); return TPM_KEYNOTFOUND; } /* 7a-c */ if (!(parentKey->usageFlags & TPM_VERIFICATION_KEY_USAGE_SIGN_RIMAUTH)) { memset(key, 0, sizeof(*key)); return TPM_INVALID_KEYUSAGE; } if ((verificationKey->usageFlags & TPM_VERIFICATION_KEY_USAGE_INCREMENT_BOOTSTRAP) && !(parentKey->usageFlags & TPM_VERIFICATION_KEY_USAGE_INCREMENT_BOOTSTRAP)) { memset(key, 0, sizeof(*key)); return TPM_INVALID_KEYUSAGE; } if (key->parentId != parentKey->myId) { debug("id mismatch: parentId = %08x keyId = %08x", key->parentId, parentKey->myId); memset(key, 0, sizeof(*key)); return TPM_AUTHFAIL; } /* 7d */ res = verify_verification_key(verificationKey, parentKey); if (res != TPM_SUCCESS) { memset(key, 0, sizeof(*key)); return res; } /* 7e-g */ if (verificationKey->referenceCounter.counterSelection > MTM_COUNTER_SELECT_MAX) return TPM_BAD_COUNTER; if (verificationKey->referenceCounter.counterSelection == MTM_COUNTER_SELECT_BOOTSTRAP) { if (verificationKey->referenceCounter.counterValue < tpmData.permanent.data.counters[MTM_COUNTER_SELECT_BOOTSTRAP].counter) return TPM_BAD_COUNTER; } if (verificationKey->referenceCounter.counterSelection == MTM_COUNTER_SELECT_RIMPROTECT) { if (verificationKey->referenceCounter.counterValue < tpmData.permanent.data.counters[MTM_COUNTER_SELECT_RIMPROTECT].counter) return TPM_BAD_COUNTER; } /* 7j */ debug("TPM_VERIFICATION_KEY_CHAIN_AUTHORIZED_LOAD"); *loadMethod = TPM_VERIFICATION_KEY_CHAIN_AUTHORIZED_LOAD; } /* store verification key */ if (store_verification_key(verificationKey, key) != 0) { debug("store_verification_key() failed"); memset(key, 0, sizeof(*key)); return TPM_FAIL; } return TPM_SUCCESS; } TPM_RESULT MTM_LoadVerificationRootKeyDisable() { info("MTM_LoadVerificationRootKeyDisable()"); mtmData.stany.flags.loadVerificationRootKeyEnabled = FALSE; mtmData.permanent.data.loadVerificationKeyMethods |= TPM_VERIFICATION_KEY_ROOT_LOAD; return TPM_SUCCESS; } TPM_RESULT MTM_VerifyRIMCert(TPM_RIM_CERTIFICATE* rimCert, TPM_VERIFICATION_KEY_HANDLE rimKeyHandle) { TPM_RESULT res; info("MTM_VerifyRIMCert()"); debug("key handle = %08x", rimKeyHandle); /* 1 */ if (rimCert == NULL || rimCert->tag != TPM_TAG_RIM_CERTIFICATE) return TPM_BAD_PARAMETER; /* 2 */ if (rimCert->parentId == TPM_VERIFICATION_KEY_ID_NONE) return TPM_AUTHFAIL; /* 3 */ if (rimCert->parentId == TPM_VERIFICATION_KEY_ID_INTERNAL) { return verify_rim_certificate(rimCert); } else { /* 4 */ MTM_KEY_DATA *rimKey = mtm_get_key(rimKeyHandle); if (rimKey == NULL) return TPM_KEYNOTFOUND; if ((rimKey->usageFlags & TPM_VERIFICATION_KEY_USAGE_SIGN_RIMCERT) == 0) return TPM_INVALID_KEYUSAGE; if (rimCert->parentId != rimKey->myId) { debug("id mismatch: parentId = %08x keyId = %08x", rimCert->parentId, rimKey->myId); return TPM_AUTHFAIL; } res = verify_rim_certificate(rimCert); if (res != TPM_SUCCESS) return res; } /* 5 */ if (rimCert->referenceCounter.counterSelection > MTM_COUNTER_SELECT_MAX) return TPM_BAD_COUNTER; /* 6 */ if (rimCert->referenceCounter.counterSelection == MTM_COUNTER_SELECT_BOOTSTRAP) { if (rimCert->referenceCounter.counterValue < tpmData.permanent.data.counters[MTM_COUNTER_SELECT_BOOTSTRAP].counter) return TPM_BAD_COUNTER; } /* 7 */ if (rimCert->referenceCounter.counterSelection == MTM_COUNTER_SELECT_RIMPROTECT) { if (rimCert->referenceCounter.counterValue < tpmData.permanent.data.counters[MTM_COUNTER_SELECT_RIMPROTECT].counter) return TPM_BAD_COUNTER; } return TPM_SUCCESS; } TPM_RESULT MTM_VerifyRIMCertAndExtend(TPM_RIM_CERTIFICATE *rimCert, TPM_VERIFICATION_KEY_HANDLE rimKey, TPM_PCRVALUE *outDigest) { int i; TPM_RESULT res; info("MTM_VerifyRIMCertAndExtend()"); /* 1-7 */ res = MTM_VerifyRIMCert(rimCert, rimKey); if (res != TPM_SUCCESS) return res; /* 8 */ for (i = 0; i < TPM_NUM_PCR / 8; i++) { if (rimCert->state.pcrSelection.pcrSelect[i] != 0) break; } if (i < TPM_NUM_PCR / 8) { TPM_COMPOSITE_HASH digest; if (tpm_compute_pcr_digest(&rimCert->state.pcrSelection, &digest, NULL) != TPM_SUCCESS) { debug("tpm_compute_pcr_digest() failed"); return TPM_FAIL; } if (memcmp(&digest, &rimCert->state.digestAtRelease, sizeof(TPM_COMPOSITE_HASH)) != 0) return TPM_WRONGPCRVAL; } /* 9, 10 */ return TPM_Extend(rimCert->measurementPcrIndex, &rimCert->measurementValue, outDigest); } TPM_RESULT MTM_IncrementBootstrapCounter(TPM_RIM_CERTIFICATE *rimCert, TPM_VERIFICATION_KEY_HANDLE rimKeyHandle) { TPM_RESULT res; MTM_KEY_DATA* rimKey; info("MTM_IncrementBootstrapCounter()"); /* 1 */ if (rimCert == NULL || rimCert->tag != TPM_TAG_RIM_CERTIFICATE) return TPM_BAD_PARAMETER; /* 2 */ debug("rimKeyHandle = %08x", rimKeyHandle); rimKey = mtm_get_key(rimKeyHandle); if (rimKey == NULL) return TPM_KEYNOTFOUND; /* 3 */ if ((rimKey->usageFlags & TPM_VERIFICATION_KEY_USAGE_SIGN_RIMCERT) == 0 ||(rimKey->usageFlags & TPM_VERIFICATION_KEY_USAGE_INCREMENT_BOOTSTRAP) == 0) return TPM_INVALID_KEYUSAGE; /* 4 */ if (rimCert->parentId != rimKey->myId) return TPM_AUTHFAIL; /* 5 */ res = verify_rim_certificate(rimCert); if (res != TPM_SUCCESS) return res; /* 6 */ if (rimCert->referenceCounter.counterSelection > MTM_COUNTER_SELECT_MAX) return TPM_BAD_COUNTER; /* 7 */ if (rimCert->referenceCounter.counterSelection == MTM_COUNTER_SELECT_BOOTSTRAP) { if (rimCert->referenceCounter.counterValue < tpmData.permanent.data.counters[MTM_COUNTER_SELECT_BOOTSTRAP].counter) return TPM_BAD_COUNTER; tpmData.permanent.data.counters[MTM_COUNTER_SELECT_BOOTSTRAP].counter = rimCert->referenceCounter.counterValue; } return TPM_SUCCESS; } TPM_RESULT MTM_SetVerifiedPCRSelection(TPM_PCR_SELECTION *verifiedSelection, TPM_AUTH *auth1) { int i; TPM_RESULT res; info("MTM_SetVerifiedPCRSelection()"); /* verify permission */ if (tpmData.permanent.flags.owned) { res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); } else { res = FALSE; } if (!res && !mtmData.stany.flags.loadVerificationRootKeyEnabled) { return TPM_FAIL; } /* echeck if a localityModifier is set */ for (i = 0; i < TPM_NUM_PCR; i++) { if (verifiedSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { if (tpmData.permanent.data.pcrAttrib[i].pcrResetLocal) return TPM_FAIL; } } /* copy selection */ memcpy(&mtmData.permanent.data.verifiedPCRs, verifiedSelection, sizeof(TPM_PCR_SELECTION)); return TPM_SUCCESS; } ================================================ FILE: tddl/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 455 2010-09-17 18:34:04Z mast $ set(tddl-tpm-emulator_SRCS "tddl.c" "tddl-tpm-emulator.h") add_library(tddl-tpm-emulator SHARED ${tddl-tpm-emulator_SRCS}) add_library(tddl-tpm-emulator_static STATIC ${tddl-tpm-emulator_SRCS}) if(UNIX) set_target_properties(tddl-tpm-emulator PROPERTIES SOVERSION "1.2" VERSION "1.2.${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}") set_target_properties(tddl-tpm-emulator_static PROPERTIES OUTPUT_NAME tddl-tpm-emulator) elseif(WIN32) set_target_properties(tddl-tpm-emulator PROPERTIES OUTPUT_NAME ifxtpm) set_target_properties(tddl-tpm-emulator PROPERTIES PREFIX "") endif() install(TARGETS tddl-tpm-emulator DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS tddl-tpm-emulator_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES "tddl-tpm-emulator.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_executable(test_tddl test_tddl.c) target_link_libraries(test_tddl tddl-tpm-emulator_static) ================================================ FILE: tddl/tddl-tpm-emulator.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: tddl.h 364 2010-02-11 10:24:45Z mast $ */ #ifndef _TDDL_H_ #define _TDDL_H_ #include /* * The following types and functions are specified in the * TCPA Software Stack (TSS) Specification [TSS_Spec]. */ /* * Basic Data Types */ typedef uint8_t BYTE; typedef uint8_t TSS_BOOL; typedef uint32_t UINT32; typedef uint32_t TSS_RESULT; /* * TDDL Return Codes */ #define TSS_E_BASE 0x00000000 #define TDDL_SUCCESS (TSS_E_BASE + 0x00) #define TDDL_E_FAIL (TSS_E_BASE + 0x02) #define TDDL_E_BAD_PARAMETER (TSS_E_BASE + 0x03) #define TDDL_E_NOTIMPL (TSS_E_BASE + 0x06) #define TDDL_E_TIMEOUT (TSS_E_BASE + 0x12) #define TDDL_E_ALREADY_OPENED (TSS_E_BASE + 0x81) #define TDDL_E_ALREADY_CLOSED (TSS_E_BASE + 0x82) #define TDDL_E_INSUFFICIENT_BUFFER (TSS_E_BASE + 0x83) #define TDDL_E_COMMAND_COMPLETED (TSS_E_BASE + 0x84) #define TDDL_E_COMMAND_ABORTED (TSS_E_BASE + 0x85) #define TDDL_E_IOERROR (TSS_E_BASE + 0x87) #define TDDL_E_BADTAG (TSS_E_BASE + 0x88) #define TDDL_E_COMPONENT_NOT_FOUND (TSS_E_BASE + 0x89) /* * Capability Flag Definitions */ #define TDDL_CAP_VERSION 0x0100 #define TDDL_CAP_VER_DRV 0x0101 #define TDDL_CAP_VER_FW 0x0102 #define TDDL_CAP_VER_FW_DATE 0x0103 #define TDDL_CAP_PROPERTY 0x0200 #define TDDL_CAP_PROP_MANUFACTURER 0x0201 #define TDDL_CAP_PROP_MODULE_TYPE 0x0202 #define TDDL_CAP_PROP_GLOBAL_STATE 0x0203 /* * Driver and Device Status Codes */ #define TDDL_DRIVER_STATUS 0x0010 #define TDDL_DRIVER_OK 0x0010 #define TDDL_DRIVER_FAILED 0x0011 #define TDDL_DRIVER_NOT_OPENED 0x0012 #define TDDL_DEVICE_STATUS 0x0020 #define TDDL_DEVICE_OK 0x0020 #define TDDL_DEVICE_UNRECOVERABLE 0x0021 #define TDDL_DEVICE_RECOVERABLE 0x0022 #define TDDL_DEVICE_NOT_FOUND 0x0023 /* * TDDL Interface Functions */ #ifdef __cplusplus extern "C" { #endif /** * Tddli_Open - establish a connection to the TPM device driver * * This function establishes a connection with the TPM device driver. The * application utilizing the TPM DDL is guaranteed to have exclusive access * to the TPM device. This function must be called before calling GetStatus, * GetCapability, SetCapability, or TransmitData. */ TSS_RESULT Tddli_Open(void); /** * Tddli_Close - close a open connection to the TPM device driver * * This function closes a connection with the TPM device driver. Following * a successful response to this function, the TPM device driver can clean * up any resources used to maintain a connection with the TPM device driver * library. */ TSS_RESULT Tddli_Close(void); /** * Tddli_Cancel - cancels the last outstanding TPM command * * This function cancels an outstanding TPM command. An application can call * this function, in a separate context, to interrupt a TPM command that has * not completed. The TPM device driver must acknowledge this function if * it has not returned from a previous TPM command and return * TDDL_COMMAND_ABORTED for the call in process. */ TSS_RESULT Tddli_Cancel(void); /** * Tddli_GetCapability - read the attributes returned by the TPM * * @CapArea: [in] Partition of capabilities to be interrogated. * @SubCap: [in] Subcode of the requested capabilities. * @pCapBuf: [out] Pointer to a buffer containing the received attribute data. * @puntCapBufLen: [in] Size of the receive buffer in bytes. [out] Number of written bytes. * * This function queries the TPM hardware, firmware and device driver * attributes such as firmware version, driver version, etc. */ TSS_RESULT Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen); /** * Tddli_SetCapability - set parameters to the TPM * * @CapArea: [in] Partition of capabilities to be set. * @SubCap: [in] Subcode of the capabilities to be set. * @pCapBuf: [in] Pointer to a buffer containing the capability data to set. * @puntCapBufLen: [in] Size of the request buffer in bytes. * * This function sets parameters in the TPM hardware, firmware and device * driver attributes. An application can set TPM device driver and operating * parameters that may be defined by the TPM vendor. For now, the parameter * definitions are vendor-defined. */ TSS_RESULT Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen); /** * Tddli_GetStatus - get status of the TPM driver and device TDDLI * * @ReqStatusType: [in] Requested type of status information. * @puntStatus: [out] Requested status. * * This function queries the status the TPM driver and device. An application * can determine the health of the TPM subsystem by utilizing this function. */ TSS_RESULT Tddli_GetStatus(UINT32 ReqStatusType, UINT32* puntStatus); /** * Tddli_TransmitData - send any data to the TPM module TDDLI * * @pTransmitBuf: [in] Pointer to a buffer containing TPM transmit data. * @TransmitBufLen: [in] Size of TPM transmit data in bytes. * @pReceiveBuf: [out] Pointer to a buffer containing TPM receive data * @puntReceiveBufLen: [in] Size of TPM receive buffer in bytes. * [out] Number of written bytes. * * The function sends a TPM command directly to a TPM device driver, causing * the TPM to perform the corresponding operation. */ TSS_RESULT Tddli_TransmitData(BYTE* pTransmitBuf, UINT32 TransmitBufLen, BYTE* pReceiveBuf, UINT32* puntReceiveBufLen); /** * Tddli_SetPowerManagement - sets and queries the TPM's power states * * @SendSaveStateCommand: [in] * @QuerySetNewTPMPowerState: [in] * [out] * * This function sets and queries the TPM’s power states. */ TSS_RESULT Tddli_SetPowerManagement(TSS_BOOL SendSaveStateCommand, UINT32 *QuerySetNewTPMPowerState); /** * Tddli_PowerManagementControl - gets and sets the power state management * * @SendPowerManager: [in] * @DriverManagesPowerStates: [out] * * This command determines and sets which component, TCS or the Driver, * receives and handles the platform’s OS power state management signals. */ TSS_RESULT Tddli_PowerManagementControl(TSS_BOOL SendPowerManager, UINT32 DriverManagesPowerStates); #ifdef __cplusplus } #endif #endif /* _TDDL_H_ */ ================================================ FILE: tddl/tddl.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: tddl.c 364 2010-02-11 10:24:45Z mast $ */ #include #include #include #include "tddl-tpm-emulator.h" /* device and socket names */ static const char *tpm_device_name = TPM_DEVICE_NAME; static const char *tpmd_socket_name = TPM_SOCKET_NAME; /* TPM device handle */ static int tddli_dh = -1; /* status of the TPM device driver and the TPM itself */ static TSS_RESULT tddli_driver_status = TDDL_DRIVER_FAILED; static TSS_RESULT tddli_device_status = TDDL_DEVICE_NOT_FOUND; #if defined(_WIN32) || defined(_WIN64) #include "tddl_windows.h" #else #include "tddl_unix.h" #endif TSS_RESULT Tddli_Open() { TSS_RESULT res; tddli_mutex_lock(&tddli_lock); if (tddli_dh != -1) { res = TDDL_E_ALREADY_OPENED; } else { res = open_socket(tpmd_socket_name); if (res != TDDL_SUCCESS) { res = open_device(tpm_device_name); } } tddli_mutex_unlock(&tddli_lock); return res; } TSS_RESULT Tddli_Close() { TSS_RESULT res = TDDL_SUCCESS; tddli_mutex_lock(&tddli_lock); if (tddli_dh >= 0) { close(tddli_dh); tddli_dh = -1; } else { res = TDDL_E_ALREADY_CLOSED; } tddli_mutex_unlock(&tddli_lock); return res; } TSS_RESULT Tddli_Cancel() { /* this is not supported by the TPM emulator */ return TDDL_E_NOTIMPL; } static TSS_RESULT send_to_tpm(BYTE* pTransmitBuf, UINT32 TransmitBufLen) { ssize_t res; res = write(tddli_dh, pTransmitBuf, TransmitBufLen); if (res < 0 || (UINT32)res != TransmitBufLen) return TDDL_E_IOERROR; return TDDL_SUCCESS; } static TSS_RESULT receive_from_tpm(BYTE* pReceiveBuf, UINT32* puntReceiveBufLen) { ssize_t res; uint32_t len; if (*puntReceiveBufLen < 10) return TDDL_E_INSUFFICIENT_BUFFER; res = read(tddli_dh, pReceiveBuf, *puntReceiveBufLen); if (res < 10) return TDDL_E_IOERROR; *puntReceiveBufLen = res; len = ((uint32_t)pReceiveBuf[2] << 24) | ((uint32_t)pReceiveBuf[3] << 16) | ((uint32_t)pReceiveBuf[4] << 8) | (uint32_t)pReceiveBuf[5]; if (len != *puntReceiveBufLen) return TDDL_E_INSUFFICIENT_BUFFER; return TDDL_SUCCESS; } TSS_RESULT Tddli_TransmitData(BYTE* pTransmitBuf, UINT32 TransmitBufLen, BYTE* pReceiveBuf, UINT32* puntReceiveBufLen) { TSS_RESULT res; tddli_mutex_lock(&tddli_lock); if (tddli_dh >= 0) { res = send_to_tpm(pTransmitBuf, TransmitBufLen); if (res == TDDL_SUCCESS) res = receive_from_tpm(pReceiveBuf, puntReceiveBufLen); } else { res = TDDL_E_FAIL; } tddli_mutex_unlock(&tddli_lock); return res; } static TSS_RESULT cap_version(UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen) { TSS_RESULT res; UINT32 len = 18; BYTE buf[18]; switch (SubCap) { case TDDL_CAP_VER_DRV: if (*puntCapBufLen < 4) return TDDL_E_INSUFFICIENT_BUFFER; *puntCapBufLen = 4; memcpy(pCapBuf, "\x01\x05\x00\x00", 4); return TDDL_SUCCESS; case TDDL_CAP_VER_FW: if (*puntCapBufLen < 4) return TDDL_E_INSUFFICIENT_BUFFER; *puntCapBufLen = 4; res = send_to_tpm((uint8_t*)"\x00\xc1\x00\x00\x00\x12\x00\x00\x00\x65" "\x00\x00\x00\x06\x00\x00\x00\x00", 18); if (res != TDDL_SUCCESS) return res; res = receive_from_tpm(buf, &len); if (res != TDDL_SUCCESS) return res; if (len != 18 || (buf[6] | buf[7] | buf[8] | buf[9]) != 0) return TDDL_E_FAIL; memcpy(pCapBuf, &buf[14], 4); return TDDL_SUCCESS; case TDDL_CAP_VER_FW_DATE: /* this is not yet supported by the TPM emulator */ return TDDL_E_NOTIMPL; default: return TDDL_E_BAD_PARAMETER; } } static TSS_RESULT cap_property(UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen) { static const char *manufacturer = "Mario Strasser, ETH Zurich"; static const char *type = "Software-based TPM Emulator"; switch (SubCap) { case TDDL_CAP_PROP_MANUFACTURER: if (*puntCapBufLen < strlen(manufacturer)) return TDDL_E_INSUFFICIENT_BUFFER; *puntCapBufLen = strlen(manufacturer); memcpy(pCapBuf, manufacturer, *puntCapBufLen); return TDDL_SUCCESS; case TDDL_CAP_PROP_MODULE_TYPE: if (*puntCapBufLen < strlen(type)) return TDDL_E_INSUFFICIENT_BUFFER; *puntCapBufLen = strlen(type); memcpy(pCapBuf, type, *puntCapBufLen); return TDDL_SUCCESS; default: return TDDL_E_BAD_PARAMETER; } } TSS_RESULT Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen) { TSS_RESULT res = TDDL_SUCCESS; if (tddli_dh < 0) return TDDL_E_FAIL; tddli_mutex_lock(&tddli_lock); switch (CapArea) { case TDDL_CAP_VERSION: res = cap_version(SubCap, pCapBuf, puntCapBufLen); break; case TDDL_CAP_PROPERTY: res = cap_property(SubCap, pCapBuf, puntCapBufLen); break; default: res = TDDL_E_BAD_PARAMETER; } tddli_mutex_unlock(&tddli_lock); return res; } TSS_RESULT Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen) { /* no vendor-specific capabilities available, yet */ return TDDL_E_BAD_PARAMETER; } TSS_RESULT Tddli_GetStatus(UINT32 ReqStatusType, UINT32* puntStatus) { TSS_RESULT res = TDDL_SUCCESS; tddli_mutex_lock(&tddli_lock); switch (ReqStatusType) { case TDDL_DRIVER_STATUS: *puntStatus = tddli_driver_status; break; case TDDL_DEVICE_STATUS: *puntStatus = tddli_device_status; break; default: res = TDDL_E_BAD_PARAMETER; } tddli_mutex_unlock(&tddli_lock); return res; } TSS_RESULT Tddli_SetPowerManagement(TSS_BOOL SendSaveStateCommand, UINT32 *QuerySetNewTPMPowerState) { return TDDL_E_NOTIMPL; } TSS_RESULT Tddli_PowerManagementControl(TSS_BOOL SendPowerManager, UINT32 DriverManagesPowerStates) { return TDDL_E_NOTIMPL; } /* * Export also TDDL_* function aliases as they are * used by some non standard-conform applications. */ TSS_RESULT TDDL_Open() { return Tddli_Open(); } TSS_RESULT TDDL_Close() { return Tddli_Close(); } TSS_RESULT TDDL_Cancel() { return Tddli_Cancel(); } TSS_RESULT TDDL_TransmitData(BYTE* pTransmitBuf, UINT32 TransmitBufLen, BYTE* pReceiveBuf, UINT32* puntReceiveBufLen) { return Tddli_TransmitData(pTransmitBuf, TransmitBufLen, pReceiveBuf, puntReceiveBufLen); } TSS_RESULT TDDL_GetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen) { return Tddli_GetCapability(CapArea, SubCap, pCapBuf, puntCapBufLen); } TSS_RESULT TDDL_SetCapability(UINT32 CapArea, UINT32 SubCap, BYTE* pCapBuf, UINT32* puntCapBufLen) { return Tddli_SetCapability(CapArea, SubCap, pCapBuf, puntCapBufLen); } TSS_RESULT TDDL_GetStatus(UINT32 ReqStatusType, UINT32* puntStatus) { return Tddli_GetStatus(ReqStatusType, puntStatus); } TSS_RESULT TDDL_SetPowerManagement(TSS_BOOL SendSaveStateCommand, UINT32 *QuerySetNewTPMPowerState) { return Tddli_SetPowerManagement(SendSaveStateCommand, QuerySetNewTPMPowerState); } TSS_RESULT TDDL_PowerManagementControl(TSS_BOOL SendPowerManager, UINT32 DriverManagesPowerStates) { return Tddli_PowerManagementControl(SendPowerManager, DriverManagesPowerStates); } ================================================ FILE: tddl/tddl_unix.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: tddl.c 364 2010-02-11 10:24:45Z mast $ */ #include #include #include #include #include #include #include #include /* library lock */ static pthread_mutex_t tddli_lock = PTHREAD_MUTEX_INITIALIZER; #define tddli_mutex_lock(a) pthread_mutex_lock(a) #define tddli_mutex_unlock(a) pthread_mutex_unlock(a) static TSS_RESULT open_device(const char *device_name) { tddli_dh = open(device_name, O_RDWR); if (tddli_dh < 0) { if (errno == ENOENT || errno == ENXIO) { tddli_driver_status = TDDL_DRIVER_FAILED; tddli_device_status = TDDL_DEVICE_NOT_FOUND; } else { tddli_driver_status = TDDL_DRIVER_NOT_OPENED; tddli_device_status = TDDL_DEVICE_RECOVERABLE; } return TDDL_E_FAIL; } else { tddli_driver_status = TDDL_DRIVER_OK; tddli_device_status = TDDL_DEVICE_OK; return TDDL_SUCCESS; } } static TSS_RESULT open_socket(const char *socket_name) { struct sockaddr_un addr; tddli_dh = socket(AF_UNIX, SOCK_STREAM, 0); if (tddli_dh < 0) { tddli_driver_status = TDDL_DRIVER_FAILED; tddli_device_status = TDDL_DEVICE_NOT_FOUND; return TDDL_E_FAIL; } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path)-1); if (connect(tddli_dh, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) { tddli_driver_status = TDDL_DRIVER_FAILED; tddli_device_status = TDDL_DEVICE_NOT_FOUND; return TDDL_E_FAIL; } tddli_driver_status = TDDL_DRIVER_OK; tddli_device_status = TDDL_DEVICE_OK; return TDDL_SUCCESS; } ================================================ FILE: tddl/tddl_windows.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: tddl.c 364 2010-02-11 10:24:45Z mast $ */ #include #include #include #include #include #include "tddl.h" /* library lock */ static CRITICAL_SECTION tddli_lock; #define tddli_mutex_lock(a) EnterCriticalSection(a) #define tddli_mutex_unlock(a) LeaveCriticalSection(a) BOOL APIENTRY DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved) { switch(reason) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&tddli_lock); break; case DLL_PROCESS_DETACH: DeleteCriticalSection(&tddli_lock); break; default: break; } return TRUE; } static TSS_RESULT open_device(const char *device_name) { /* open the named pipe and generate a posix file handle */ DWORD mode = PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE; HANDLE ph = CreateFile(device_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); SetNamedPipeHandleState(ph, &mode, NULL, NULL); tddli_dh = _open_osfhandle((DWORD)ph, O_RDWR | O_BINARY); if (tddli_dh < 0) { if (errno == ENOENT || errno == ENXIO) { tddli_driver_status = TDDL_DRIVER_FAILED; tddli_device_status = TDDL_DEVICE_NOT_FOUND; } else { tddli_driver_status = TDDL_DRIVER_NOT_OPENED; tddli_device_status = TDDL_DEVICE_RECOVERABLE; } return TDDL_E_FAIL; } else { tddli_driver_status = TDDL_DRIVER_OK; tddli_device_status = TDDL_DEVICE_OK; return TDDL_SUCCESS; } } static TSS_RESULT open_socket(const char *socket_name) { return TDDL_E_FAIL; } ================================================ FILE: tddl/test_tddl.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: test_tddl.c 364 2010-02-11 10:24:45Z mast $ */ #include #include const char *get_error(TSS_RESULT res) { switch (res) { case TDDL_SUCCESS: return "success"; case TDDL_E_FAIL: return "operation failed"; case TDDL_E_BAD_PARAMETER: return "bad patameter"; case TDDL_E_TIMEOUT: return "timeout"; case TDDL_E_ALREADY_OPENED: return "already opened"; case TDDL_E_ALREADY_CLOSED: return "already closed"; case TDDL_E_INSUFFICIENT_BUFFER: return "insufficient buffer"; case TDDL_E_COMMAND_COMPLETED: return "comand completed"; case TDDL_E_COMMAND_ABORTED: return "command aborted"; case TDDL_E_IOERROR: return "IO error"; case TDDL_E_BADTAG: return "bad tag"; case TDDL_E_COMPONENT_NOT_FOUND: return "component not found"; default: return "unknown error"; } } const char *get_status(UINT32 status) { switch (status) { case TDDL_DRIVER_OK: return "DRIVER OK"; case TDDL_DRIVER_FAILED: return "DRIVER FAILED"; case TDDL_DRIVER_NOT_OPENED: return "DRIVER NOT OPENED"; case TDDL_DEVICE_OK: return "DEVICE OK"; case TDDL_DEVICE_UNRECOVERABLE: return "DEVICE UNRECOVERABLE"; case TDDL_DEVICE_RECOVERABLE: return "DEVICE RECOVERABLE"; case TDDL_DEVICE_NOT_FOUND: return "DEVICE NOT FOUND"; default: return ""; } } int main() { TSS_RESULT res; UINT32 status; BYTE buf[256]; UINT32 buf_size = sizeof(buf); BYTE reset[] = {0, 193, 0, 0, 0, 10, 0, 0, 0, 90}; unsigned int i; res = Tddli_Open(); if (res != TDDL_SUCCESS) { printf("Error: Tddli_Open() failed: %s (%04x)\n", get_error(res), res); return -1; } /* get driver and device status */ res = Tddli_GetStatus(TDDL_DRIVER_STATUS, &status); if (res != TDDL_SUCCESS) { printf("Error: Tddli_GetStatus() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } printf("Driver status: %s\n", get_status(status)); res = Tddli_GetStatus(TDDL_DEVICE_STATUS, &status); if (res != TDDL_SUCCESS) { printf("Error: Tddli_GetStatus() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } printf("Device status: %s\n", get_status(status)); /* get version */ buf_size = sizeof(buf); res = Tddli_GetCapability(TDDL_CAP_VERSION, TDDL_CAP_VER_DRV, buf, &buf_size); if (res != TDDL_SUCCESS) { printf("Error: Tddli_GetCapability() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } printf("DRV version: %d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3]); buf_size = sizeof(buf); res = Tddli_GetCapability(TDDL_CAP_VERSION, TDDL_CAP_VER_FW, buf, &buf_size); if (res != TDDL_SUCCESS) { printf("Error: Tddli_GetCapability() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } printf("TPM Version: %d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3]); /* get properties */ buf_size = sizeof(buf); res = Tddli_GetCapability(TDDL_CAP_PROPERTY, TDDL_CAP_PROP_MANUFACTURER, buf, &buf_size); if (res != TDDL_SUCCESS) { printf("Error: Tddli_GetCapability() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } buf[buf_size] = 0; printf("Manufacturer: %s\n", buf); buf_size = sizeof(buf); res = Tddli_GetCapability(TDDL_CAP_PROPERTY, TDDL_CAP_PROP_MODULE_TYPE, buf, &buf_size); if (res != TDDL_SUCCESS) { printf("Error: Tddli_GetCapability() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } buf[buf_size] = 0; printf("Module type: %s\n", buf); /* reset tpm */ printf("Transmit: "); for (i = 0; i < sizeof(reset); i++) printf("%02x ", reset[i]); printf("\n"); buf_size = sizeof(buf); res = Tddli_TransmitData(reset, sizeof(reset), buf, &buf_size); if (res != TDDL_SUCCESS) { printf("Error: Tddli_TransmitData() failed: %s (%04x)\n", get_error(res), res); Tddli_Close(); return -1; } printf("Result: "); for (i = 0; i < buf_size; i++) printf("%02x ", buf[i]); printf("\n"); res = Tddli_Close(); if (res != TDDL_SUCCESS) { printf("Error: Tddli_Close() failed: %s (%04x)\n", get_error(res), res); return -1; } return 0; } ================================================ FILE: tpm/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 364 2010-02-11 10:24:45Z mast $ file(GLOB tpm_SRCS "*.[h|c]") add_library(tpm STATIC ${tpm_SRCS}) ================================================ FILE: tpm/tpm_audit.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_audit.c 385 2010-02-17 15:41:28Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_marshalling.h" #include "tpm_handles.h" #include /* * Auditing ([TPM_Part3], Section 8) * The TPM generates an audit event in response to the TPM executing a * function that has the audit flag set to TRUE for that function. The * TPM maintains an extended value for all audited operations. */ #define AUDIT_STATUS tpmData.permanent.data.ordinalAuditStatus void tpm_audit_request(TPM_COMMAND_CODE ordinal, TPM_REQUEST *req) { tpm_sha1_ctx_t sha1_ctx; BYTE buf[sizeof_TPM_AUDIT_EVENT_IN(x)], *ptr; UINT32 len; TPM_COMMAND_CODE ord = ordinal & TPM_ORD_INDEX_MASK; if (ord < TPM_ORD_MAX && (AUDIT_STATUS[ord / 8] & (1 << (ord & 0x07)))) { info("tpm_audit_request()"); /* is there already an audit session running? */ if (!tpmData.stany.data.auditSession) { tpmData.stany.data.auditSession = TRUE; tpmData.permanent.data.auditMonotonicCounter++; } /* update audit digest */ ptr = buf; len = sizeof(buf); tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_AUDIT_EVENT_IN); tpm_marshal_TPM_COMMAND_CODE(&ptr, &len, ordinal); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, req->param, req->paramSize); tpm_sha1_final(&sha1_ctx, ptr); ptr += 20; len -= 20; tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_COUNTER_VALUE); tpm_marshal_UINT32(&ptr, &len, 0); tpm_marshal_UINT32(&ptr, &len, tpmData.permanent.data.auditMonotonicCounter); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, tpmData.stany.data.auditDigest.digest, sizeof(TPM_DIGEST)); tpm_sha1_update(&sha1_ctx, buf, sizeof(buf)); tpm_sha1_final(&sha1_ctx, tpmData.stany.data.auditDigest.digest); } } void tpm_audit_response(TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp) { tpm_sha1_ctx_t sha1_ctx; BYTE buf[sizeof_TPM_AUDIT_EVENT_OUT(x)], *ptr; UINT32 len; TPM_COMMAND_CODE ord = ordinal & TPM_ORD_INDEX_MASK; if (ord < TPM_ORD_MAX && (AUDIT_STATUS[ord / 8] & (1 << (ord & 0x07)))) { info("tpm_audit_response()"); /* update audit digest */ ptr = buf; len = sizeof(buf); tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_AUDIT_EVENT_OUT); tpm_marshal_TPM_COMMAND_CODE(&ptr, &len, ordinal); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, rsp->param, rsp->paramSize); tpm_sha1_final(&sha1_ctx, ptr); ptr += 20; len -= 20; tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_COUNTER_VALUE); tpm_marshal_UINT32(&ptr, &len, 0); tpm_marshal_UINT32(&ptr, &len, tpmData.permanent.data.auditMonotonicCounter); tpm_marshal_TPM_RESULT(&ptr, &len, rsp->result); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, tpmData.stany.data.auditDigest.digest, sizeof(TPM_DIGEST)); tpm_sha1_update(&sha1_ctx, buf, sizeof(buf)); tpm_sha1_final(&sha1_ctx, tpmData.stany.data.auditDigest.digest); } } /* number of bits to represent 0, 1, 2, 3 ... */ static uint8_t bits[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; TPM_RESULT TPM_GetAuditDigest(UINT32 startOrdinal, TPM_COUNTER_VALUE *counterValue, TPM_DIGEST *auditDigest, BOOL *more, UINT32 *ordSize, UINT32 **ordList) { UINT32 i, j, len, *ptr; info("TPM_GetAuditDigest()"); /* compute (maximal) size of the ordinal list */ for (len = 0, i = startOrdinal/8; i < TPM_ORD_MAX/8; i++) { len += bits[AUDIT_STATUS[i] & 0x0f]; len += bits[(AUDIT_STATUS[i] >> 4) & 0x0f]; } /* setup ordinal list */ ptr = *ordList = tpm_malloc(len); if (ptr == NULL) return TPM_FAIL; for (*ordSize = 0, i = startOrdinal/8; i < TPM_ORD_MAX/8; i++) { if (AUDIT_STATUS[i]) for (j = 0; j < 8; j++) { if ((AUDIT_STATUS[i] & (1 << j)) && i * 8 + j > startOrdinal) { *ptr++ = i * 8 + j; *ordSize += 4; } } } counterValue->tag = TPM_TAG_COUNTER_VALUE; memset(counterValue->label, 0, sizeof(counterValue->label)); counterValue->counter = tpmData.permanent.data.auditMonotonicCounter; memcpy(auditDigest, &tpmData.stany.data.auditDigest, sizeof(TPM_DIGEST)); if (more != NULL) *more = FALSE; return TPM_SUCCESS; } TPM_RESULT TPM_GetAuditDigestSigned(TPM_KEY_HANDLE keyHandle, BOOL closeAudit, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_COUNTER_VALUE *counterValue, TPM_DIGEST *auditDigest, TPM_DIGEST *ordinalDigest, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; UINT32 ordSize; UINT32 *ordList; BYTE buf[TPM_ORD_MAX * 4]; BYTE *ptr; UINT32 len; tpm_sha1_ctx_t ctx; info("TPM_GetAuditDigestSigned()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_IDENTITY && key->keyUsage != TPM_KEY_LEGACY) return TPM_INVALID_KEYUSAGE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } /* get audit digest */ res = TPM_GetAuditDigest(0, counterValue, auditDigest, NULL, &ordSize, &ordList); if (res != TPM_SUCCESS) return res; /* allocate buffer memory */ len = sizeof(buf); ptr = buf; if (tpm_marshal_UINT32_ARRAY(&ptr, &len, ordList, ordSize/4) != 0) { debug("tpm_marshal_UINT32_ARRAY() failed."); tpm_free(ordList); return TPM_FAIL; } tpm_free(ordList); /* compute ordinal digest */ tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, buf, ordSize); tpm_sha1_final(&ctx, ordinalDigest->digest); /* setup a TPM_SIGN_INFO structure */ memset(buf, 0, sizeof(buf)); memcpy(&buf[0], "\x00\x05", 2); memcpy(&buf[2], "ADIG", 4); memcpy(&buf[6], antiReplay->nonce, 20); len = sizeof(buf) - 26; ptr = &buf[26]; if (tpm_marshal_UINT32(&ptr, &len, 20 + sizeof_TPM_COUNTER_VALUE((*counterValue)) + 20) != 0) { debug("tpm_marshal_UINT32() failed."); return TPM_FAIL; } memcpy(ptr, auditDigest->digest, 20); len -= 20; ptr += 20; if (tpm_marshal_TPM_COUNTER_VALUE(&ptr, &len, counterValue) != 0) { debug("tpm_marshal_TPM_COUNTER_VALUE() failed."); return TPM_FAIL; } memcpy(ptr, ordinalDigest->digest, 20); /* check key usage */ if (closeAudit) { if (key->keyUsage == TPM_KEY_IDENTITY) { memset(&tpmData.stany.data.auditDigest, 0, sizeof(TPM_DIGEST)); } else { return TPM_INVALID_KEYUSAGE; } } /* sign data */ if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { debug("TPM_SS_RSASSAPKCS1v15_SHA1"); len = 30 + 20 + sizeof_TPM_COUNTER_VALUE((*counterValue)) + 20; tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, buf, len); tpm_sha1_final(&ctx, buf); res = tpm_sign(key, auth1, FALSE, buf, SHA1_DIGEST_LENGTH, sig, sigSize); } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) { debug("TPM_SS_RSASSAPKCS1v15_INFO"); res = tpm_sign(key, auth1, TRUE, buf, sizeof(buf), sig, sigSize); } else { debug("unsupported signature scheme: %02x", key->sigScheme); res = TPM_INVALID_KEYUSAGE; } return res; } TPM_RESULT TPM_SetOrdinalAuditStatus(TPM_COMMAND_CODE ordinalToAudit, BOOL auditState, TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_SetOrdinalAuditStatus()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* set ordinal's audit status */ if (ordinalToAudit > TPM_ORD_MAX) return TPM_BADINDEX; ordinalToAudit &= TPM_ORD_INDEX_MASK; if (auditState) { AUDIT_STATUS[ordinalToAudit / 8] |= (1 << (ordinalToAudit & 0x07)); } else { AUDIT_STATUS[ordinalToAudit / 8] &= ~(1 << (ordinalToAudit & 0x07)); } return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_authorization.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_authorization.c 467 2011-07-19 17:36:12Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_handles.h" #include "tpm_data.h" #include "tpm_marshalling.h" #include "crypto/hmac.h" #include "crypto/sha1.h" /* * Authorization Changing ([TPM_Part3], Section 17) */ 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 (tpm_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 (tpm_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) { TPM_STORE_ASYMKEY store; BYTE *store_buf; /* decrypt entity */ if (tpm_decrypt_private_key(parent, encData, encDataSize, &store, &store_buf, NULL)) return TPM_DECRYPT_ERROR; /* verify auth2 */ res = tpm_verify_auth(auth2, store.usageAuth, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res; /* change usageAuth and use it also for auth2 */ memcpy(store.usageAuth, plainAuth, sizeof(TPM_SECRET)); /* encrypt entity */ *outDataSize = parent->key.size >> 3; *outData = tpm_malloc(*outDataSize); if (tpm_encrypt_private_key(parent, &store, *outData, outDataSize)) { tpm_free(encData); tpm_free(store_buf); return TPM_ENCRYPT_ERROR; } tpm_free(store_buf); } else { return TPM_WRONG_ENTITYTYPE; } return TPM_SUCCESS; } TPM_RESULT TPM_ChangeAuthOwner(TPM_PROTOCOL_ID protocolID, TPM_ENCAUTH *newAuth, TPM_ENTITY_TYPE entityType, TPM_AUTH *auth1) { TPM_RESULT res; TPM_SESSION_DATA *session; TPM_SECRET plainAuth; int i; info("TPM_ChangeAuthOwner()"); /* 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) return TPM_AUTHFAIL; /* decrypt auth */ tpm_decrypt_auth_secret(*newAuth, session->sharedSecret, &session->lastNonceEven, plainAuth); /* change authorization data */ if (entityType == TPM_ET_OWNER) { memcpy(tpmData.permanent.data.ownerAuth, plainAuth, sizeof(TPM_SECRET)); /* invalidate all associated sessions but the current one */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpmData.stany.data.sessions[i].handle == TPM_KH_OWNER && &tpmData.stany.data.sessions[i] != session) { memset(&tpmData.stany.data.sessions[i], 0, sizeof(TPM_SESSION_DATA)); } } } else if (entityType == TPM_ET_SRK) { memcpy(tpmData.permanent.data.srk.usageAuth, plainAuth, sizeof(TPM_SECRET)); /* probably not correct; spec. v1.2 rev94 says nothing about authDataUsage tpmData.permanent.data.srk.authDataUsage = TPM_AUTH_ALWAYS; */ /* invalidate all associated sessions but the current one */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpmData.stany.data.sessions[i].handle == TPM_KH_SRK && &tpmData.stany.data.sessions[i] != session) { memset(&tpmData.stany.data.sessions[i], 0, sizeof(TPM_SESSION_DATA)); } } } else { return TPM_WRONG_ENTITYTYPE; } return TPM_SUCCESS; } /* * Authorization Sessions ([TPM_Part3], Section 18) */ TPM_RESULT TPM_OIAP(TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven) { TPM_SESSION_DATA *session; info("TPM_OIAP()"); /* get a free session if any is left */ *authHandle = tpm_get_free_session(TPM_ST_OIAP); session = tpm_get_auth(*authHandle); if (session == NULL) return TPM_RESOURCES; /* setup session */ tpm_get_random_bytes(nonceEven->nonce, sizeof(nonceEven->nonce)); memcpy(&session->nonceEven, nonceEven, sizeof(TPM_NONCE)); debug("handle = %08x", *authHandle); return TPM_SUCCESS; } TPM_RESULT TPM_OSAP(TPM_ENTITY_TYPE entityType, UINT32 entityValue, TPM_NONCE *nonceOddOSAP, TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven, TPM_NONCE *nonceEvenOSAP) { tpm_hmac_ctx_t ctx; TPM_SESSION_DATA *session; TPM_SECRET *secret = NULL; info("TPM_OSAP()"); /* get a free session if any is left */ *authHandle = tpm_get_free_session(TPM_ST_OSAP); session = tpm_get_auth(*authHandle); if (session == NULL) return TPM_RESOURCES; debug("entityType = %04x, entityValue = %04x", entityType, entityValue); /* check whether ADIP encryption scheme is supported */ switch (entityType & 0xFF00) { case TPM_ET_XOR: break; default: return TPM_INAPPROPRIATE_ENC; } /* get resource handle and the respective secret */ switch (entityType & 0x00FF) { case TPM_ET_KEYHANDLE: session->handle = entityValue; if (session->handle == TPM_KH_OPERATOR) return TPM_BAD_HANDLE; if (tpm_get_key(session->handle) != NULL) secret = &tpm_get_key(session->handle)->usageAuth; else debug("TPM_OSAP failed(): tpm_get_key(handle) == NULL"); break; case TPM_ET_OWNER: case TPM_ET_VERIFICATION_AUTH: session->handle = TPM_KH_OWNER; if (tpmData.permanent.flags.owned) secret = &tpmData.permanent.data.ownerAuth; break; case TPM_ET_SRK: session->handle = TPM_KH_SRK; if (tpmData.permanent.data.srk.payload) secret = &tpmData.permanent.data.srk.usageAuth; break; case TPM_ET_COUNTER: session->handle = entityValue; if (tpm_get_counter(session->handle) != NULL) secret = &tpm_get_counter(session->handle)->usageAuth; break; case TPM_ET_NV: session->handle = entityValue; if (tpm_get_nvs(session->handle) != NULL) secret = &tpm_get_nvs(session->handle)->authValue; break; default: return TPM_BAD_PARAMETER; } if (secret == NULL) { debug("TPM_OSAP failed(): secret == NULL"); memset(session, 0, sizeof(*session)); return TPM_BAD_PARAMETER; } /* save entity type */ session->entityType = entityType; /* generate nonces */ tpm_get_random_bytes(nonceEven->nonce, sizeof(nonceEven->nonce)); memcpy(&session->nonceEven, nonceEven, sizeof(TPM_NONCE)); tpm_get_random_bytes(nonceEvenOSAP->nonce, sizeof(nonceEvenOSAP->nonce)); /* compute shared secret */ tpm_hmac_init(&ctx, *secret, sizeof(*secret)); tpm_hmac_update(&ctx, nonceEvenOSAP->nonce, sizeof(nonceEvenOSAP->nonce)); tpm_hmac_update(&ctx, nonceOddOSAP->nonce, sizeof(nonceOddOSAP->nonce)); tpm_hmac_final(&ctx, session->sharedSecret); debug("handle = %08x", *authHandle); return TPM_SUCCESS; } TPM_RESULT TPM_DSAP(TPM_ENTITY_TYPE entityType, TPM_KEY_HANDLE keyHandle, TPM_NONCE *nonceOddDSAP, UINT32 entityValueSize, BYTE *entityValue, TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven, TPM_NONCE *nonceEvenDSAP) { tpm_hmac_ctx_t ctx; TPM_SESSION_DATA *session; TPM_SECRET secret; TPM_FAMILY_TABLE_ENTRY *fr; info("TPM_DSAP()"); /* get a free session if any is left */ *authHandle = tpm_get_free_session(TPM_ST_DSAP); session = tpm_get_auth(*authHandle); if (session == NULL) return TPM_RESOURCES; debug("entityType = %04x, entityValueSize = %04x", entityType, entityValueSize); /* decode entity value and get respective secret */ if (entityType == TPM_ET_DEL_OWNER_BLOB) { TPM_DELEGATE_OWNER_BLOB blob; TPM_DELEGATE_SENSITIVE sens; BYTE *sens_buf; TPM_DIGEST blobDigest; /* unmarshal the entity value */ if (tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(&entityValue, &entityValueSize, &blob) || blob.tag != TPM_TAG_DELEGATE_OWNER_BLOB) return TPM_WRONG_ENTITYTYPE; /* validate the integrity of the blob */ tpm_compute_owner_blob_digest(&blob, &blobDigest); if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* get family table row */ debug("family id = %d", blob.pub.familyID); fr = tpm_get_family_row(blob.pub.familyID); if (fr == NULL) return TPM_BADINDEX; if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (fr->verificationCount != blob.pub.verificationCount) return TPM_FAIL; /* decrypt sensitive data */ if (tpm_decrypt_sensitive(blob.additionalArea, blob.additionalSize, blob.sensitiveArea, blob.sensitiveSize, &sens, &sens_buf)) { debug("tpm_decrypt_sensitive() failed"); return TPM_DECRYPT_ERROR; } if (sens.tag != TPM_TAG_DELEGATE_SENSITIVE) { tpm_free(sens_buf); return TPM_BAD_DELEGATE; } memcpy(&secret, &sens.authValue, sizeof(TPM_SECRET)); memcpy(&session->permissions, &blob.pub.permissions, sizeof(TPM_DELEGATIONS)); session->handle = TPM_KH_OWNER; session->familyID = blob.pub.familyID; tpm_free(sens_buf); } else if (entityType == TPM_ET_DEL_ROW) { UINT32 row; TPM_DELEGATE_TABLE_ROW *dr; if (tpm_unmarshal_UINT32(&entityValue, &entityValueSize, &row)) return TPM_WRONG_ENTITYTYPE; debug("row number = %d", row); dr = tpm_get_delegate_row(row); if (dr == NULL) return TPM_BADINDEX; fr = tpm_get_family_row(dr->pub.familyID); if (fr == NULL) return TPM_BADINDEX; if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (fr->verificationCount != dr->pub.verificationCount) return TPM_FAIL; memcpy(&secret, dr->authValue, sizeof(TPM_SECRET)); memcpy(&session->permissions, &dr->pub.permissions, sizeof(TPM_DELEGATIONS)); session->handle = keyHandle; session->familyID = dr->pub.familyID; } else if (entityType == TPM_ET_DEL_KEY_BLOB) { TPM_DELEGATE_KEY_BLOB blob; TPM_DELEGATE_SENSITIVE sens; BYTE *sens_buf; TPM_DIGEST blobDigest; TPM_KEY_DATA *key; TPM_PUBKEY pubKey; /* unmarshal the entity value */ if (tpm_unmarshal_TPM_DELEGATE_KEY_BLOB(&entityValue, &entityValueSize, &blob) || blob.tag != TPM_TAG_DELEGATE_KEY_BLOB) return TPM_WRONG_ENTITYTYPE; /* validate the integrity of the blob */ tpm_compute_key_blob_digest(&blob, &blobDigest); if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* validate key digest */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_KEYNOTFOUND; if (tpm_extract_pubkey(key, &pubKey) != 0) { debug("tpm_extract_pubkey() failed."); return TPM_FAIL; } if (tpm_compute_pubkey_digest(&pubKey, &blobDigest) != 0) { debug("tpm_compute_pubkey_digest() failed."); free_TPM_PUBKEY(pubKey); return TPM_FAIL; } free_TPM_PUBKEY(pubKey); if (memcmp(&blob.pubKeyDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_KEYNOTFOUND; /* get family table row */ debug("family id = %d", blob.pub.familyID); fr = tpm_get_family_row(blob.pub.familyID); if (fr == NULL) return TPM_BADINDEX; if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (fr->verificationCount != blob.pub.verificationCount) return TPM_FAIL; /* decrypt sensitive data */ if (tpm_decrypt_sensitive(blob.additionalArea, blob.additionalSize, blob.sensitiveArea, blob.sensitiveSize, &sens, &sens_buf)) { debug("tpm_decrypt_sensitive() failed"); return TPM_DECRYPT_ERROR; } if (sens.tag != TPM_TAG_DELEGATE_SENSITIVE) { tpm_free(sens_buf); return TPM_BAD_DELEGATE; } memcpy(&secret, &sens.authValue, sizeof(TPM_SECRET)); memcpy(&session->permissions, &blob.pub.permissions, sizeof(TPM_DELEGATIONS)); session->handle = keyHandle; session->familyID = blob.pub.familyID; tpm_free(sens_buf); } else { return TPM_BAD_PARAMETER; } /* save entity type */ session->entityType = entityType; /* generate nonces */ tpm_get_random_bytes(nonceEven->nonce, sizeof(nonceEven->nonce)); memcpy(&session->nonceEven, nonceEven, sizeof(TPM_NONCE)); tpm_get_random_bytes(nonceEvenDSAP->nonce, sizeof(nonceEvenDSAP->nonce)); /* compute shared secret */ tpm_hmac_init(&ctx, secret, sizeof(secret)); tpm_hmac_update(&ctx, nonceEvenDSAP->nonce, sizeof(nonceEvenDSAP->nonce)); tpm_hmac_update(&ctx, nonceOddDSAP->nonce, sizeof(nonceOddDSAP->nonce)); tpm_hmac_final(&ctx, session->sharedSecret); debug("handle = %08x", *authHandle); return TPM_SUCCESS; } TPM_RESULT TPM_SetOwnerPointer(TPM_ENTITY_TYPE entityType, UINT32 entityValue) { info("TPM_SetOwnerPointer() is not supported"); return TPM_DISABLED_CMD; } #define IS_SET(val, mask) (((val) & (mask)) == (mask)) static BOOL is_owner_delegation_permitted(TPM_COMMAND_CODE ordinal, UINT32 per1, UINT32 per2) { switch (ordinal) { case TPM_ORD_SetOrdinalAuditStatus: return IS_SET(per1, TPM_DELEGATE_SetOrdinalAuditStatus); case TPM_ORD_DirWriteAuth: return IS_SET(per1, TPM_DELEGATE_DirWriteAuth); case TPM_ORD_CMK_ApproveMA: return IS_SET(per1, TPM_DELEGATE_CMK_ApproveMA); case TPM_ORD_NV_WriteValue: return IS_SET(per1, TPM_DELEGATE_NV_WriteValue); case TPM_ORD_CMK_CreateTicket: return IS_SET(per1, TPM_DELEGATE_CMK_CreateTicket); case TPM_ORD_NV_ReadValue: return IS_SET(per1, TPM_DELEGATE_NV_ReadValue); case TPM_ORD_Delegate_LoadOwnerDelegation: return IS_SET(per1, TPM_DELEGATE_Delegate_LoadOwnerDelegation); case TPM_ORD_DAA_Join: return IS_SET(per1, TPM_DELEGATE_DAA_Join); case TPM_ORD_AuthorizeMigrationKey: return IS_SET(per1, TPM_DELEGATE_AuthorizeMigrationKey); case TPM_ORD_CreateMaintenanceArchive: return IS_SET(per1, TPM_DELEGATE_CreateMaintenanceArchive); case TPM_ORD_LoadMaintenanceArchive: return IS_SET(per1, TPM_DELEGATE_LoadMaintenanceArchive); case TPM_ORD_KillMaintenanceFeature: return IS_SET(per1, TPM_DELEGATE_KillMaintenanceFeature); case TPM_ORD_OwnerReadInternalPub: return IS_SET(per1, TPM_DELEGATE_OwnerReadInternalPub); case TPM_ORD_ResetLockValue: return IS_SET(per1, TPM_DELEGATE_ResetLockValue); case TPM_ORD_OwnerClear: return IS_SET(per1, TPM_DELEGATE_OwnerClear); case TPM_ORD_DisableOwnerClear: return IS_SET(per1, TPM_DELEGATE_DisableOwnerClear); case TPM_ORD_NV_DefineSpace: return IS_SET(per1, TPM_DELEGATE_NV_DefineSpace); case TPM_ORD_OwnerSetDisable: return IS_SET(per1, TPM_DELEGATE_OwnerSetDisable); case TPM_ORD_SetCapability: return IS_SET(per1, TPM_DELEGATE_SetCapability); case TPM_ORD_MakeIdentity: return IS_SET(per1, TPM_DELEGATE_MakeIdentity); case TPM_ORD_ActivateIdentity: return IS_SET(per1, TPM_DELEGATE_ActivateIdentity); case TPM_ORD_OwnerReadPubek: return IS_SET(per1, TPM_DELEGATE_OwnerReadPubek); case TPM_ORD_DisablePubekRead: return IS_SET(per1, TPM_DELEGATE_DisablePubekRead); case TPM_ORD_SetRedirection: return IS_SET(per1, TPM_DELEGATE_SetRedirection); case TPM_ORD_FieldUpgrade: return IS_SET(per1, TPM_DELEGATE_FieldUpgrade); case TPM_ORD_Delegate_UpdateVerification: return IS_SET(per1, TPM_DELEGATE_Delegate_UpdateVerification); case TPM_ORD_CreateCounter: return IS_SET(per1, TPM_DELEGATE_CreateCounter); case TPM_ORD_ReleaseCounterOwner: return IS_SET(per1, TPM_DELEGATE_ReleaseCounterOwner); case TPM_ORD_Delegate_Manage: return IS_SET(per1, TPM_DELEGATE_Delegate_Manage); case TPM_ORD_Delegate_CreateOwnerDelegation: return IS_SET(per1, TPM_DELEGATE_Delegate_CreateOwnerDelegation); case TPM_ORD_DAA_Sign: return IS_SET(per1, TPM_DELEGATE_DAA_Sign); } return FALSE; } static BOOL is_key_delegation_permitted(TPM_COMMAND_CODE ordinal, UINT32 per1, UINT32 per2) { switch (ordinal) { case TPM_ORD_CMK_ConvertMigration: return IS_SET(per1, TPM_KEY_DELEGATE_CMK_ConvertMigration); case TPM_ORD_TickStampBlob: return IS_SET(per1, TPM_KEY_DELEGATE_TickStampBlob); case TPM_ORD_ChangeAuthAsymStart: return IS_SET(per1, TPM_KEY_DELEGATE_ChangeAuthAsymStart); case TPM_ORD_ChangeAuthAsymFinish: return IS_SET(per1, TPM_KEY_DELEGATE_ChangeAuthAsymFinish); case TPM_ORD_CMK_CreateKey: return IS_SET(per1, TPM_KEY_DELEGATE_CMK_CreateKey); case TPM_ORD_MigrateKey: return IS_SET(per1, TPM_KEY_DELEGATE_MigrateKey); case TPM_ORD_LoadKey2: return IS_SET(per1, TPM_KEY_DELEGATE_LoadKey2); case TPM_ORD_EstablishTransport: return IS_SET(per1, TPM_KEY_DELEGATE_EstablishTransport); case TPM_ORD_ReleaseTransportSigned: return IS_SET(per1, TPM_KEY_DELEGATE_ReleaseTransportSigned); case TPM_ORD_Quote2: return IS_SET(per1, TPM_KEY_DELEGATE_Quote2); case TPM_ORD_Sealx: return IS_SET(per1, TPM_KEY_DELEGATE_Sealx); case TPM_ORD_MakeIdentity: return IS_SET(per1, TPM_KEY_DELEGATE_MakeIdentity); case TPM_ORD_ActivateIdentity: return IS_SET(per1, TPM_KEY_DELEGATE_ActivateIdentity); case TPM_ORD_GetAuditDigestSigned: return IS_SET(per1, TPM_KEY_DELEGATE_GetAuditDigestSigned); case TPM_ORD_Sign: return IS_SET(per1, TPM_KEY_DELEGATE_Sign); case TPM_ORD_CertifyKey2: return IS_SET(per1, TPM_KEY_DELEGATE_CertifyKey2); case TPM_ORD_CertifyKey: return IS_SET(per1, TPM_KEY_DELEGATE_CertifyKey); case TPM_ORD_CreateWrapKey: return IS_SET(per1, TPM_KEY_DELEGATE_CreateWrapKey); case TPM_ORD_CMK_CreateBlob: return IS_SET(per1, TPM_KEY_DELEGATE_CMK_CreateBlob); case TPM_ORD_CreateMigrationBlob: return IS_SET(per1, TPM_KEY_DELEGATE_CreateMigrationBlob); case TPM_ORD_ConvertMigrationBlob: return IS_SET(per1, TPM_KEY_DELEGATE_ConvertMigrationBlob); case TPM_ORD_Delegate_CreateKeyDelegation: return IS_SET(per1, TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation); case TPM_ORD_ChangeAuth: return IS_SET(per1, TPM_KEY_DELEGATE_ChangeAuth); case TPM_ORD_GetPubKey: return IS_SET(per1, TPM_KEY_DELEGATE_GetPubKey); case TPM_ORD_Quote: return IS_SET(per1, TPM_KEY_DELEGATE_Quote); case TPM_ORD_Unseal: return IS_SET(per1, TPM_KEY_DELEGATE_Unseal); case TPM_ORD_Seal: return IS_SET(per1, TPM_KEY_DELEGATE_Seal); case TPM_ORD_LoadKey: return IS_SET(per1, TPM_KEY_DELEGATE_LoadKey); } return FALSE; } TPM_RESULT tpm_verify_auth(TPM_AUTH *auth, TPM_SECRET secret, TPM_HANDLE handle) { tpm_hmac_ctx_t ctx; TPM_SESSION_DATA *session; BYTE digest[SHA1_DIGEST_LENGTH]; info("tpm_verify_auth()"); debug("handle = %08x", auth->authHandle); /* get dedicated authorization or transport session */ session = tpm_get_auth(auth->authHandle); if (session == NULL) session = tpm_get_transport(auth->authHandle); if (session == NULL) return TPM_INVALID_AUTHHANDLE; /* setup authorization */ if (session->type == TPM_ST_OIAP) { debug("[TPM_ST_OIAP]"); /* We copy the secret because it might be deleted or invalidated afterwards, but we need it again for authorizing the response. */ memcpy(session->sharedSecret, secret, sizeof(TPM_SECRET)); } else if (session->type == TPM_ST_OSAP) { debug("[TPM_ST_OSAP]"); if (session->handle != handle) return TPM_AUTHFAIL; } else if (session->type == TPM_ST_DSAP) { debug("[TPM_ST_DSAP]"); if (session->handle != handle) return TPM_AUTHFAIL; /* check permissions */ debug("delegation type = %d", session->permissions.delegateType); if (session->permissions.delegateType == TPM_DEL_OWNER_BITS) { if (!is_owner_delegation_permitted(auth->ordinal, session->permissions.per1, session->permissions.per2)) return TPM_DISABLED_CMD; } else if (session->permissions.delegateType == TPM_DEL_KEY_BITS) { if (!is_key_delegation_permitted(auth->ordinal, session->permissions.per1, session->permissions.per2)) return TPM_DISABLED_CMD; } else { return TPM_AUTHFAIL; } } else if (session->type == TPM_ST_TRANSPORT) { debug("[TPM_ST_TRANSPORT]"); memcpy(session->sharedSecret, session->transInternal.authData, sizeof(TPM_SECRET)); } else { return TPM_INVALID_AUTHHANDLE; } memcpy(auth->secret, session->sharedSecret, sizeof(TPM_SECRET)); /* verify authorization */ tpm_hmac_init(&ctx, auth->secret, sizeof(auth->secret)); tpm_hmac_update(&ctx, auth->digest, sizeof(auth->digest)); tpm_hmac_update(&ctx, session->nonceEven.nonce, sizeof(session->nonceEven.nonce)); tpm_hmac_update(&ctx, auth->nonceOdd.nonce, sizeof(auth->nonceOdd.nonce)); tpm_hmac_update(&ctx, &auth->continueAuthSession, 1); tpm_hmac_final(&ctx, digest); if (memcmp(digest, auth->auth, sizeof(auth->auth))) return TPM_AUTHFAIL; /* generate new nonceEven */ memcpy(&session->lastNonceEven, &session->nonceEven, sizeof(TPM_NONCE)); tpm_get_random_bytes(auth->nonceEven.nonce, sizeof(auth->nonceEven.nonce)); memcpy(&session->nonceEven, &auth->nonceEven, sizeof(TPM_NONCE)); return TPM_SUCCESS; } void tpm_decrypt_auth_secret(TPM_ENCAUTH encAuth, TPM_SECRET secret, TPM_NONCE *nonce, TPM_SECRET plainAuth) { unsigned int i; tpm_sha1_ctx_t ctx; tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, secret, sizeof(TPM_SECRET)); tpm_sha1_update(&ctx, nonce->nonce, sizeof(nonce->nonce)); tpm_sha1_final(&ctx, plainAuth); for (i = 0; i < sizeof(TPM_SECRET); i++) plainAuth[i] ^= encAuth[i]; } ================================================ FILE: tpm/tpm_capability.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * 2005-2008 Heiko Stamer * * 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_capability.c 446 2010-06-12 10:44:08Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_marshalling.h" #include "tpm_data.h" #include "tpm_handles.h" /* * The GetCapability Commands ([TPM_Part3], Section 7) * The GetCapability command allows the TPM to report back to the requester * what type of TPM it is dealing with. The request for information requires * the requester to specify which piece of information that is required. */ static inline TPM_RESULT return_UINT32(UINT32 *respSize, BYTE **resp, UINT32 value) { UINT32 len = *respSize = 4; BYTE *ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, value)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; } static inline TPM_RESULT return_UINT32_array(UINT32 *respSize, BYTE **resp, UINT32 *array, UINT32 array_len) { UINT32 len = *respSize = 4 * array_len; BYTE *ptr = *resp = tpm_malloc(*respSize); if (ptr == NULL || tpm_marshal_UINT32_ARRAY(&ptr, &len, array, array_len)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; } static 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; } 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].payload) 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]"); return return_UINT32(respSize, resp, TPM_NUM_FAMILY_TABLE_ENTRY); case TPM_CAP_PROP_TIS_TIMEOUT: debug("[TPM_CAP_PROP_TIS_TIMEOUT]"); return return_UINT32_array(respSize, resp, tpmData.permanent.data.tis_timeouts, TPM_NUM_TIS_TIMEOUTS); case TPM_CAP_PROP_STARTUP_EFFECT: debug("[TPM_CAP_PROP_STARTUP_EFFECT]"); return return_UINT32(respSize, resp, 0x4f); case TPM_CAP_PROP_DELEGATE_ROW: debug("[TPM_CAP_PROP_DELEGATE_ROW]"); return return_UINT32(respSize, resp, TPM_NUM_DELEGATE_TABLE_ENTRY); case TPM_CAP_PROP_MAX_DAASESS: debug("[TPM_CAP_PROP_MAX_DAASESS]"); return return_UINT32(respSize, resp, TPM_MAX_SESSIONS_DAA); case TPM_CAP_PROP_DAASESS: debug("[TPM_CAP_PROP_DAASESS]"); 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]"); return return_UINT32(respSize, resp, 0xfffffffe); 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]"); return return_UINT32(respSize, resp, tpmData.permanent.data.restrictDelegate); case TPM_CAP_PROP_DURATION: debug("[TPM_CAP_PROP_DURATION]"); return return_UINT32_array(respSize, resp, tpmData.permanent.data.cmd_durations, TPM_NUM_CMD_DURATIONS); case TPM_CAP_PROP_ACTIVE_COUNTER: debug("[TPM_CAP_PROP_ACTIVE_COUNTER]"); return return_UINT32(respSize, resp, tpmData.stclear.data.countID); case TPM_CAP_PROP_MAX_NV_AVAILABLE: debug("[TPM_CAP_PROP_MAX_NV_AVAILABLE]"); return return_UINT32(respSize, resp, TPM_MAX_NV_SIZE - tpmData.permanent.data.nvDataSize); case TPM_CAP_PROP_INPUT_BUFFER: debug("[TPM_CAP_PROP_INPUT_BUFFER]"); return return_UINT32(respSize, resp, TPM_CMD_BUF_SIZE); default: return TPM_BAD_MODE; } } /* changed since v1.2 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; } /* manufacturer specific */ static TPM_RESULT cap_mfr(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { UINT32 len, type; BYTE *ptr; if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &type)) return TPM_BAD_MODE; switch (type) { default: *respSize = 4; 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 TPM_RESULT cap_nv_list(UINT32 *respSize, BYTE **resp) { UINT32 i, len; BYTE *ptr = *resp = tpm_malloc(TPM_MAX_NVS * sizeof(TPM_NV_INDEX)); if (ptr == NULL) return TPM_FAIL; *respSize = 0; for (i = 0; i < TPM_MAX_NVS; i++) { if (tpmData.permanent.data.nvStorage[i].valid) { len = sizeof(TPM_NV_INDEX); ptr = (*resp) + *respSize; *respSize += len; if (tpm_marshal_UINT32(&ptr, &len, tpmData.permanent.data.nvStorage[i].pubInfo.nvIndex)) { tpm_free(*resp); return TPM_FAIL; } } } return TPM_SUCCESS; } static TPM_RESULT cap_nv_index(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_NV_INDEX nvIndex; TPM_NV_DATA_SENSITIVE *nv; UINT32 len; BYTE *ptr; if (tpm_unmarshal_TPM_NV_INDEX(&subCap, &subCapSize, &nvIndex)) return TPM_BAD_MODE; nv = tpm_get_nvs(nvIndex); if (nv == NULL) return TPM_BADINDEX; len = *respSize = sizeof_TPM_NV_DATA_PUBLIC(nv->pubInfo); ptr = *resp = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_NV_DATA_PUBLIC(&ptr, &len, &nv->pubInfo)) { tpm_free(*resp); return TPM_FAIL; } *respSize -= len; 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].payload) { 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; 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: debug("[TPM_RT_CONTEXT]"); for (i = 0; i < TPM_MAX_SESSION_LIST; i++) if (tpmData.stany.data.contextList[i] != 0) { list.loaded++; list.handle[i] = tpmData.stany.data.contextList[i]; } break; 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_ord(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_COMMAND_CODE ord; if (tpm_unmarshal_TPM_COMMAND_CODE(&subCap, &subCapSize, &ord)) return TPM_BAD_MODE; switch (ord) { case TPM_ORD_Init: case TPM_ORD_Startup: case TPM_ORD_SaveState: case TPM_ORD_SelfTestFull: case TPM_ORD_ContinueSelfTest: case TPM_ORD_GetTestResult: case TPM_ORD_SetOwnerInstall: case TPM_ORD_OwnerSetDisable: case TPM_ORD_PhysicalEnable: case TPM_ORD_PhysicalDisable: case TPM_ORD_PhysicalSetDeactivated: case TPM_ORD_SetTempDeactivated: case TPM_ORD_SetOperatorAuth: case TPM_ORD_TakeOwnership: case TPM_ORD_OwnerClear: case TPM_ORD_ForceClear: case TPM_ORD_DisableOwnerClear: case TPM_ORD_DisableForceClear: case TSC_ORD_PhysicalPresence: case TSC_ORD_ResetEstablishmentBit: case TPM_ORD_GetCapability: case TPM_ORD_SetCapability: case TPM_ORD_GetCapabilityOwner: case TPM_ORD_GetAuditDigest: case TPM_ORD_GetAuditDigestSigned: case TPM_ORD_SetOrdinalAuditStatus: case TPM_ORD_FieldUpgrade: case TPM_ORD_SetRedirection: case TPM_ORD_ResetLockValue: case TPM_ORD_Seal: case TPM_ORD_Unseal: case TPM_ORD_UnBind: case TPM_ORD_CreateWrapKey: case TPM_ORD_LoadKey2: case TPM_ORD_GetPubKey: case TPM_ORD_Sealx: case TPM_ORD_CreateMigrationBlob: case TPM_ORD_ConvertMigrationBlob: case TPM_ORD_AuthorizeMigrationKey: case TPM_ORD_MigrateKey: case TPM_ORD_CMK_SetRestrictions: case TPM_ORD_CMK_ApproveMA: case TPM_ORD_CMK_CreateKey: case TPM_ORD_CMK_CreateTicket: case TPM_ORD_CMK_CreateBlob: case TPM_ORD_CMK_ConvertMigration: case TPM_ORD_CreateMaintenanceArchive: case TPM_ORD_LoadMaintenanceArchive: case TPM_ORD_KillMaintenanceFeature: case TPM_ORD_LoadManuMaintPub: case TPM_ORD_ReadManuMaintPub: case TPM_ORD_SHA1Start: case TPM_ORD_SHA1Update: case TPM_ORD_SHA1Complete: case TPM_ORD_SHA1CompleteExtend: case TPM_ORD_Sign: case TPM_ORD_GetRandom: case TPM_ORD_StirRandom: case TPM_ORD_CertifyKey: case TPM_ORD_CertifyKey2: case TPM_ORD_CreateEndorsementKeyPair: case TPM_ORD_CreateRevocableEK: case TPM_ORD_RevokeTrust: case TPM_ORD_ReadPubek: case TPM_ORD_OwnerReadInternalPub: case TPM_ORD_MakeIdentity: case TPM_ORD_ActivateIdentity: case TPM_ORD_Extend: case TPM_ORD_PCRRead: case TPM_ORD_Quote: case TPM_ORD_PCR_Reset: case TPM_ORD_Quote2: case TPM_ORD_ChangeAuth: case TPM_ORD_ChangeAuthOwner: case TPM_ORD_OIAP: case TPM_ORD_OSAP: case TPM_ORD_DSAP: case TPM_ORD_SetOwnerPointer: case TPM_ORD_Delegate_Manage: case TPM_ORD_Delegate_CreateKeyDelegation: case TPM_ORD_Delegate_CreateOwnerDelegation: case TPM_ORD_Delegate_LoadOwnerDelegation: case TPM_ORD_Delegate_ReadTable: case TPM_ORD_Delegate_UpdateVerification: case TPM_ORD_Delegate_VerifyDelegation: case TPM_ORD_NV_DefineSpace: case TPM_ORD_NV_WriteValue: case TPM_ORD_NV_WriteValueAuth: case TPM_ORD_NV_ReadValue: case TPM_ORD_NV_ReadValueAuth: case TPM_ORD_KeyControlOwner: case TPM_ORD_SaveContext: case TPM_ORD_LoadContext: case TPM_ORD_FlushSpecific: case TPM_ORD_GetTicks: case TPM_ORD_TickStampBlob: case TPM_ORD_EstablishTransport: case TPM_ORD_ExecuteTransport: case TPM_ORD_ReleaseTransportSigned: case TPM_ORD_CreateCounter: case TPM_ORD_IncrementCounter: case TPM_ORD_ReadCounter: case TPM_ORD_ReleaseCounter: case TPM_ORD_ReleaseCounterOwner: case TPM_ORD_DAA_Join: case TPM_ORD_DAA_Sign: /* Deprecated but supported are the following commands */ case TPM_ORD_EvictKey: case TPM_ORD_Terminate_Handle: case TPM_ORD_SaveKeyContext: case TPM_ORD_LoadKeyContext: case TPM_ORD_SaveAuthContext: case TPM_ORD_LoadAuthContext: case TPM_ORD_DirWriteAuth: case TPM_ORD_DirRead: case TPM_ORD_ChangeAuthAsymStart: case TPM_ORD_ChangeAuthAsymFinish: case TPM_ORD_Reset: case TPM_ORD_OwnerReadPubek: case TPM_ORD_DisablePubekRead: case TPM_ORD_LoadKey: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_alg(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_ALGORITHM_ID id; if (tpm_unmarshal_TPM_ALGORITHM_ID(&subCap, &subCapSize, &id)) return TPM_BAD_MODE; switch (id) { case TPM_ALG_RSA: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_pid(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_PROTOCOL_ID id; if (tpm_unmarshal_TPM_PROTOCOL_ID(&subCap, &subCapSize, &id)) return TPM_BAD_MODE; switch (id) { case TPM_PID_OIAP: case TPM_PID_OSAP: case TPM_PID_ADIP: case TPM_PID_ADCP: case TPM_PID_OWNER: case TPM_PID_DSAP: case TPM_PID_TRANSPORT: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static 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 (ptr == NULL || 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 (ptr == NULL || tpm_marshal_TPM_STCLEAR_FLAGS(&ptr, &len, &tpmData.stclear.flags)) { tpm_free(*resp); return TPM_FAIL; } return TPM_SUCCESS; default: return TPM_BAD_MODE; } } static TPM_RESULT cap_loaded(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { int i; BOOL free_space = FALSE; TPM_KEY_PARMS parms; if (tpm_unmarshal_TPM_KEY_PARMS(&subCap, &subCapSize, &parms)) return TPM_BAD_MODE; for (i = 0; i < TPM_MAX_KEYS; i++) if (!tpmData.permanent.data.keys[i].payload) free_space = TRUE; if (free_space && parms.algorithmID == TPM_ALG_RSA && parms.parms.rsa.keyLength <= 2048 && parms.parms.rsa.numPrimes == 2) return return_BOOL(respSize, resp, TRUE); return return_BOOL(respSize, resp, FALSE); } static TPM_RESULT cap_auth_encrypt(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_ALGORITHM_ID id; if (tpm_unmarshal_TPM_ALGORITHM_ID(&subCap, &subCapSize, &id)) return TPM_BAD_MODE; switch (id) { case TPM_ALG_XOR: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_sym_mode(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_SYM_MODE mode; if (tpm_unmarshal_TPM_SYM_MODE(&subCap, &subCapSize, &mode)) return TPM_BAD_MODE; switch (mode) { case TPM_ES_SYM_CTR: case TPM_ES_SYM_OFB: default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_key_status(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_KEY_HANDLE handle; TPM_KEY_DATA *key; if (tpm_unmarshal_TPM_KEY_HANDLE(&subCap, &subCapSize, &handle)) return TPM_BAD_MODE; key = tpm_get_key(handle); if (key == NULL) return TPM_INVALID_KEYHANDLE; return return_BOOL(respSize, resp, key->keyControl & TPM_KEY_CONTROL_OWNER_EVICT); } static TPM_RESULT cap_trans_alg(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_ALGORITHM_ID id; if (tpm_unmarshal_TPM_ALGORITHM_ID(&subCap, &subCapSize, &id)) return TPM_BAD_MODE; switch (id) { case TPM_ALG_RSA: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_trans_es(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_ENC_SCHEME es; if (tpm_unmarshal_TPM_ENC_SCHEME(&subCap, &subCapSize, &es)) return TPM_BAD_MODE; switch (es) { case TPM_ES_RSAESOAEP_SHA1_MGF1: case TPM_ES_RSAESPKCSv15: return return_BOOL(respSize, resp, TRUE); default: return return_BOOL(respSize, resp, FALSE); } } static TPM_RESULT cap_select_size(UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { TPM_SELECT_SIZE size; if (tpm_unmarshal_TPM_SELECT_SIZE(&subCap, &subCapSize, &size)) return TPM_BAD_MODE; return return_BOOL(respSize, resp, (size.reqSize <= TPM_NUM_PCR/8)); } static 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 = 0x0002; /* see [TPM_Part2], Section 21.6 */ version.errataRev = 0x01; /* 0x01 = rev 94, 0x02 = rev 103 */ len = 4, ptr = version.tpmVendorID; if (tpm_marshal_UINT32(&ptr, &len, TPM_MANUFACTURER)) return TPM_FAIL; 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_GetCapability(TPM_CAPABILITY_AREA capArea, UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp) { info("TPM_GetCapability()"); switch (capArea) { case TPM_CAP_ORD: debug("[TPM_CAP_ORD]"); return cap_ord(subCapSize, subCap, respSize, resp); case TPM_CAP_ALG: debug("[TPM_CAP_ALG]"); return cap_alg(subCapSize, subCap, respSize, resp); case TPM_CAP_PID: debug("[TPM_CAP_PID]"); return cap_pid(subCapSize, subCap, respSize, resp); case TPM_CAP_FLAG: debug("[TPM_CAP_FLAG]"); return cap_flag(subCapSize, subCap, respSize, resp); case TPM_CAP_PROPERTY: debug("[TPM_CAP_PROPERTY]"); return cap_property(subCapSize, subCap, respSize, resp); case TPM_CAP_VERSION: debug("[TPM_CAP_VERSION]"); return cap_version(respSize, resp); case TPM_CAP_KEY_HANDLE: debug("[TPM_CAP_KEY_HANDLE]"); BYTE buf[4]; buf[0] = (TPM_RT_KEY >> 24) & 0xff; buf[1] = (TPM_RT_KEY >> 16) & 0xff; buf[2] = (TPM_RT_KEY >> 8) & 0xff; buf[3] = TPM_RT_KEY & 0xff; return cap_handle(4, buf, respSize, resp); case TPM_CAP_CHECK_LOADED: debug("[TPM_CAP_CHECK_LOADED]"); return cap_loaded(subCapSize, subCap, respSize, resp); case TPM_CAP_SYM_MODE: debug("[TPM_CAP_SYM_MODE]"); return cap_sym_mode(subCapSize, subCap, respSize, resp); case TPM_CAP_KEY_STATUS: debug("[TPM_CAP_KEY_STATUS]"); return cap_key_status(subCapSize, subCap, respSize, resp); case TPM_CAP_NV_LIST: debug("[TPM_CAP_NV_LIST]"); return cap_nv_list(respSize, resp); case TPM_CAP_MFR: debug("[TPM_CAP_MFR]"); return cap_mfr(subCapSize, subCap, respSize, resp); case TPM_CAP_NV_INDEX: debug("[TPM_CAP_NV_INDEX]"); return cap_nv_index(subCapSize, subCap, respSize, resp); case TPM_CAP_TRANS_ALG: debug("[TPM_CAP_TRANS_ALG]"); return cap_trans_alg(subCapSize, subCap, respSize, resp); case TPM_CAP_HANDLE: debug("[TPM_CAP_HANDLE]"); return cap_handle(subCapSize, subCap, respSize, resp); case TPM_CAP_TRANS_ES: debug("[TPM_CAP_TRANS_ES]"); return cap_trans_es(subCapSize, subCap, respSize, resp); case TPM_CAP_AUTH_ENCRYPT: debug("[TPM_CAP_AUTH_ENCRYPT]"); return cap_auth_encrypt(subCapSize, subCap, respSize, resp); case TPM_CAP_SELECT_SIZE: debug("[TPM_CAP_SELECT_SIZE]"); return cap_select_size(subCapSize, subCap, respSize, resp); case TPM_CAP_VERSION_VAL: debug("[TPM_CAP_VERSION_VAL]"); return cap_version_val(respSize, resp); default: return TPM_BAD_MODE; } } static TPM_RESULT set_perm_flags(UINT32 subCap, BOOL flag, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { switch (subCap) { case 1: if (!ownerAuth && !tpm_get_physical_presence()) return TPM_AUTHFAIL; tpmData.permanent.flags.disable = flag; return TPM_SUCCESS; case 2: if (!tpm_get_physical_presence()) return TPM_AUTHFAIL; if (tpmData.permanent.flags.owned) return TPM_OWNER_SET; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; tpmData.permanent.flags.ownership = flag; return TPM_SUCCESS; case 3: if (!tpm_get_physical_presence()) return TPM_AUTHFAIL; if (disabled) return TPM_DISABLED; tpmData.permanent.flags.deactivated = flag; return TPM_SUCCESS; case 4: if (!ownerAuth) return TPM_AUTHFAIL; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; tpmData.permanent.flags.readPubek = flag; return TPM_SUCCESS; case 5: if (!ownerAuth) return TPM_AUTHFAIL; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; if (flag == FALSE) return TPM_BAD_PARAMETER; tpmData.permanent.flags.disableOwnerClear = TRUE; return TPM_SUCCESS; case 6: if (!ownerAuth) return TPM_AUTHFAIL; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; if (flag == TRUE) return TPM_BAD_PARAMETER; tpmData.permanent.flags.allowMaintenance = FALSE; return TPM_SUCCESS; case 17: if (!ownerAuth) return TPM_AUTHFAIL; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; tpmData.permanent.flags.readSRKPub = flag; return TPM_SUCCESS; case 18: if (tpmData.stany.flags.localityModifier & (TPM_LOC_THREE | TPM_LOC_FOUR)) return TPM_BAD_LOCALITY; if (flag == TRUE) return TPM_BAD_PARAMETER; tpmData.permanent.flags.tpmEstablished = FALSE; return TPM_SUCCESS; case 20: if (!ownerAuth) return TPM_AUTHFAIL; tpmData.permanent.flags.disableFullDALogicInfo = flag; return TPM_SUCCESS; } return TPM_BAD_PARAMETER; } static TPM_RESULT set_stclear_flags(UINT32 subCap, BOOL flag, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { switch (subCap) { case 2: if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; if (flag == FALSE) return TPM_BAD_PARAMETER; tpmData.stclear.flags.disableForceClear = TRUE; return TPM_SUCCESS; } return TPM_BAD_PARAMETER; } static TPM_RESULT set_stany_flags(UINT32 subCap, BOOL flag, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { switch (subCap) { case 2: if (tpmData.stany.flags.localityModifier & (TPM_LOC_THREE | TPM_LOC_FOUR)) return TPM_BAD_LOCALITY; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; if (flag == TRUE) return TPM_BAD_PARAMETER; tpmData.stany.flags.TOSPresent = FALSE; return TPM_SUCCESS; } return TPM_BAD_PARAMETER; } static TPM_RESULT set_perm_data(UINT32 subCap, BYTE *setValue, UINT32 setValueSize, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { TPM_CMK_DELEGATE del; TPM_NONCE nonce; switch (subCap) { case 16: if (tpmConf & TPM_CONF_ALLOW_PRNG_STATE_SETTING) { if (setValueSize != sizeof(tpmData.permanent.data.rngState)) return TPM_BAD_PARAMETER; memcpy(&tpmData.permanent.data.rngState, setValue, setValueSize); return TPM_SUCCESS; } else { return TPM_BAD_PARAMETER; } case 23: if (!ownerAuth) return TPM_AUTHFAIL; if (deactivated) return TPM_DEACTIVATED; if (disabled) return TPM_DISABLED; if (tpm_unmarshal_TPM_CMK_DELEGATE(&setValue, &setValueSize, &del) != 0) return TPM_BAD_PARAMETER; tpmData.permanent.data.restrictDelegate = del; return TPM_SUCCESS; case 25: if (!ownerAuth) return TPM_AUTHFAIL; if (tpm_unmarshal_TPM_NONCE(&setValue, &setValueSize, &nonce) != 0) return TPM_BAD_PARAMETER; memcpy(&tpmData.permanent.data.daaProof, &nonce, sizeof(TPM_NONCE)); return TPM_SUCCESS; } return TPM_BAD_PARAMETER; } static TPM_RESULT set_stclear_data(UINT32 subCap, BYTE *setValue, UINT32 setValueSize, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { UINT32 presence; switch (subCap) { case 23: if (tpm_unmarshal_UINT32(&setValue, &setValueSize, &presence) != 0) return TPM_BAD_PARAMETER; /* without physical presence we are only allowed to disable bits */ if (((tpmData.stclear.data.deferredPhysicalPresence | presence) != tpmData.stclear.data.deferredPhysicalPresence) && !tpm_get_physical_presence()) return TPM_BAD_PARAMETER; tpmData.stclear.data.deferredPhysicalPresence = presence; return TPM_SUCCESS; } return TPM_BAD_PARAMETER; } static TPM_RESULT set_stany_data(UINT32 subCap, BYTE *setValue, UINT32 setValueSize, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { return TPM_BAD_PARAMETER; } static TPM_RESULT set_vendor(UINT32 subCap, BYTE *setValue, UINT32 setValueSize, BOOL ownerAuth, BOOL deactivated, BOOL disabled) { /* set the capability area with the specified data, on failure deactivate the TPM */ switch (subCap) { case TPM_SET_PERM_FLAGS: debug("[TPM_SET_PERM_FLAGS]"); if (tpm_unmarshal_TPM_PERMANENT_FLAGS(&setValue, &setValueSize, &tpmData.permanent.flags) != 0) { tpmData.stclear.flags.deactivated = TRUE; return TPM_BAD_PARAMETER; } return TPM_SUCCESS; case TPM_SET_STCLEAR_FLAGS: debug("[TPM_SET_STCLEAR_FLAGS]"); if (tpm_unmarshal_TPM_STCLEAR_FLAGS(&setValue, &setValueSize, &tpmData.stclear.flags) != 0) { tpmData.stclear.flags.deactivated = TRUE; return TPM_BAD_PARAMETER; } return TPM_SUCCESS; case TPM_SET_STANY_FLAGS: debug("[TPM_SET_STANY_FLAGS]"); if (tpm_unmarshal_TPM_STANY_FLAGS(&setValue, &setValueSize, &tpmData.stany.flags) != 0) { tpmData.stclear.flags.deactivated = TRUE; return TPM_BAD_PARAMETER; } return TPM_SUCCESS; case TPM_SET_PERM_DATA: debug("[TPM_SET_PERM_DATA]"); if (tpm_unmarshal_TPM_PERMANENT_DATA(&setValue, &setValueSize, &tpmData.permanent.data) != 0) { tpmData.stclear.flags.deactivated = TRUE; return TPM_BAD_PARAMETER; } return TPM_SUCCESS; case TPM_SET_STCLEAR_DATA: debug("[TPM_SET_STCLEAR_DATA]"); if (tpm_unmarshal_TPM_STCLEAR_DATA(&setValue, &setValueSize, &tpmData.stclear.data) != 0) { tpmData.stclear.flags.deactivated = TRUE; return TPM_BAD_PARAMETER; } return TPM_SUCCESS; case TPM_SET_STANY_DATA: debug("[TPM_SET_STANY_DATA]"); if (tpm_unmarshal_TPM_STANY_DATA(&setValue, &setValueSize, &tpmData.stany.data) != 0) { tpmData.stclear.flags.deactivated = TRUE; return TPM_BAD_PARAMETER; } return TPM_SUCCESS; } return TPM_BAD_PARAMETER; } TPM_RESULT TPM_SetCapability(TPM_CAPABILITY_AREA capArea, UINT32 subCapSize, BYTE *subCap, UINT32 setValueSize, BYTE *setValue, TPM_AUTH *auth1) { TPM_RESULT res; BOOL ownerAuth = FALSE; UINT32 subCapVal; BOOL deactivated = tpmData.permanent.flags.deactivated || tpmData.stclear.flags.deactivated; BOOL disabled = tpmData.permanent.flags.disable; info("TPM_SetCapability()"); /* verify owner authorization if TPM_TAG_RQU_AUTH1_COMMAND */ if (auth1->authHandle != TPM_INVALID_HANDLE) { res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; ownerAuth = TRUE; } /* unmarshal subCap */ if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &subCapVal) != 0) return TPM_BAD_PARAMETER; /* set capability area */ switch (capArea) { case TPM_SET_PERM_FLAGS: debug("[TPM_SET_PERM_FLAGS]:%d", subCapVal); if (setValueSize != 1 || setValue[0] & 0xfe) return TPM_BAD_PARAMETER; return set_perm_flags(subCapVal, setValue[0], ownerAuth, deactivated, disabled); case TPM_SET_STCLEAR_FLAGS: debug("[TPM_SET_STCLEAR_FLAGS]:%d", subCapVal); if (setValueSize != 1 || setValue[0] & 0xfe) return TPM_BAD_PARAMETER; return set_stclear_flags(subCapVal, setValue[0], ownerAuth, deactivated, disabled); case TPM_SET_STANY_FLAGS: debug("[TPM_SET_STANY_FLAGS]:%d", subCapVal); if (setValueSize != 1 || setValue[0] & 0xfe) return TPM_BAD_PARAMETER; return set_stany_flags(subCapVal, setValue[0], ownerAuth, deactivated, disabled); case TPM_SET_PERM_DATA: debug("[TPM_SET_PERM_DATA]:%d", subCapVal); return set_perm_data(subCapVal, setValue, setValueSize, ownerAuth, deactivated, disabled); case TPM_SET_STCLEAR_DATA: debug("[TPM_SET_STCLEAR_DATA]:%d", subCapVal); return set_stclear_data(subCapVal, setValue, setValueSize, ownerAuth, deactivated, disabled); case TPM_SET_STANY_DATA: debug("[TPM_SET_STANY_DATA]:%d", subCapVal); return set_stany_data(subCapVal, setValue, setValueSize, ownerAuth, deactivated, disabled); case TPM_SET_VENDOR: debug("[TPM_SET_VENDOR]:%d", subCapVal); return set_vendor(subCapVal, setValue, setValueSize, ownerAuth, deactivated, disabled); } return TPM_BAD_PARAMETER; } TPM_RESULT TPM_GetCapabilityOwner(TPM_AUTH *auth1, TPM_VERSION *version, UINT32 *non_volatile_flags, UINT32 *volatile_flags) { TPM_RESULT res; info("TPM_GetCapabilityOwner()"); /* verify owner authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* initialize */ *version = tpmData.permanent.data.version; *non_volatile_flags = *volatile_flags = 0; /* set non-volatile flags */ if (tpmData.permanent.flags.disable) *non_volatile_flags |= (1 << 0); if (tpmData.permanent.flags.ownership) *non_volatile_flags |= (1 << 1); if (tpmData.permanent.flags.deactivated) *non_volatile_flags |= (1 << 2); if (tpmData.permanent.flags.readPubek) *non_volatile_flags |= (1 << 3); if (tpmData.permanent.flags.disableOwnerClear) *non_volatile_flags |= (1 << 4); if (tpmData.permanent.flags.allowMaintenance) *non_volatile_flags |= (1 << 5); if (tpmData.permanent.flags.physicalPresenceLifetimeLock) *non_volatile_flags |= (1 << 6); if (tpmData.permanent.flags.physicalPresenceHWEnable) *non_volatile_flags |= (1 << 7); if (tpmData.permanent.flags.physicalPresenceCMDEnable) *non_volatile_flags |= (1 << 8); if (tpmData.permanent.flags.CEKPUsed) *non_volatile_flags |= (1 << 9); if (tpmData.permanent.flags.TPMpost) *non_volatile_flags |= (1 << 10); if (tpmData.permanent.flags.TPMpostLock) *non_volatile_flags |= (1 << 11); if (tpmData.permanent.flags.FIPS) *non_volatile_flags |= (1 << 12); if (tpmData.permanent.flags.operator) *non_volatile_flags |= (1 << 13); if (tpmData.permanent.flags.enableRevokeEK) *non_volatile_flags |= (1 << 14); if (tpmData.permanent.flags.nvLocked) *non_volatile_flags |= (1 << 15); if (tpmData.permanent.flags.readSRKPub) *non_volatile_flags |= (1 << 16); if (tpmData.permanent.flags.tpmEstablished) *non_volatile_flags |= (1 << 17); if (tpmData.permanent.flags.maintenanceDone) *non_volatile_flags |= (1 << 18); if (tpmData.permanent.flags.disableFullDALogicInfo) *non_volatile_flags |= (1 << 19); /* set volatile flags */ if (tpmData.stclear.flags.deactivated) *volatile_flags |= (1 << 0); if (tpmData.stclear.flags.disableForceClear) *volatile_flags |= (1 << 1); if (tpmData.stclear.flags.physicalPresence) *volatile_flags |= (1 << 2); if (tpmData.stclear.flags.physicalPresenceLock) *volatile_flags |= (1 << 3); if (tpmData.stclear.flags.bGlobalLock) *volatile_flags |= (1 << 4); return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_cmd_handler.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_cmd_handler.c 467 2011-07-19 17:36:12Z mast $ */ #include "tpm_marshalling.h" #include "tpm_commands.h" #include "crypto/sha1.h" #include "crypto/hmac.h" #include "tpm_data.h" #include "tpm_handles.h" #ifdef MTM_EMULATOR #include "mtm/mtm_commands.h" #endif UINT32 tpm_get_in_param_offset(TPM_COMMAND_CODE ordinal) { switch (ordinal) { case TPM_ORD_ActivateIdentity: case TPM_ORD_ChangeAuth: case TPM_ORD_ChangeAuthAsymStart: case TPM_ORD_CMK_ConvertMigration: case TPM_ORD_CMK_CreateBlob: case TPM_ORD_CMK_CreateKey: case TPM_ORD_ConvertMigrationBlob: case TPM_ORD_CreateMigrationBlob: case TPM_ORD_CreateWrapKey: case TPM_ORD_Delegate_CreateKeyDelegation: case TPM_ORD_DSAP: case TPM_ORD_EstablishTransport: case TPM_ORD_EvictKey: case TPM_ORD_FlushSpecific: case TPM_ORD_GetAuditDigestSigned: case TPM_ORD_GetPubKey: case TPM_ORD_KeyControlOwner: case TPM_ORD_LoadKey: case TPM_ORD_LoadKey2: case TPM_ORD_MigrateKey: case TPM_ORD_Quote: case TPM_ORD_Quote2: case TPM_ORD_ReleaseTransportSigned: case TPM_ORD_SaveKeyContext: case TPM_ORD_Seal: case TPM_ORD_Sealx: case TPM_ORD_SetRedirection: case TPM_ORD_Sign: case TPM_ORD_TickStampBlob: case TPM_ORD_UnBind: case TPM_ORD_Unseal: case TPM_ORD_DAA_Join: case TPM_ORD_DAA_Sign: return 4; case TPM_ORD_CertifyKey: case TPM_ORD_CertifyKey2: case TPM_ORD_ChangeAuthAsymFinish: return 8; case TPM_ORD_OSAP: return 26; default: return 0; } } UINT32 tpm_get_out_param_offset(TPM_COMMAND_CODE ordinal) { switch (ordinal) { case TPM_ORD_EstablishTransport: case TPM_ORD_LoadKey2: return 4; case TPM_ORD_OIAP: return 24; case TPM_ORD_OSAP: return 44; default: return 0; } } void tpm_compute_in_param_digest(TPM_REQUEST *req) { tpm_sha1_ctx_t sha1; UINT32 offset = tpm_get_in_param_offset(req->ordinal); /* compute SHA1 hash */ if (offset <= req->paramSize) { tpm_sha1_init(&sha1); tpm_sha1_update_be32(&sha1, req->ordinal); /* skip all handles at the beginning */ tpm_sha1_update(&sha1, req->param + offset, req->paramSize - offset); tpm_sha1_final(&sha1, req->auth1.digest); memcpy(req->auth2.digest, req->auth1.digest, sizeof(req->auth1.digest)); } } void tpm_compute_out_param_digest(TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp) { tpm_sha1_ctx_t sha1; UINT32 offset = tpm_get_out_param_offset(ordinal); /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update_be32(&sha1, rsp->result); tpm_sha1_update_be32(&sha1, ordinal); tpm_sha1_update(&sha1, rsp->param + offset, rsp->paramSize - offset); tpm_sha1_final(&sha1, rsp->auth1->digest); if (rsp->auth2 != NULL) memcpy(rsp->auth2->digest, rsp->auth1->digest, sizeof(rsp->auth1->digest)); } static TPM_RESULT execute_TPM_Startup(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_STARTUP_TYPE startupType; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_STARTUP_TYPE(&ptr, &len, &startupType) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_Startup(startupType); } static TPM_RESULT execute_TPM_SaveState(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_SaveState(); } static TPM_RESULT execute_TPM_SelfTestFull(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_SelfTestFull(); } static TPM_RESULT execute_TPM_ContinueSelfTest(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_ContinueSelfTest(); } static TPM_RESULT execute_TPM_GetTestResult(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* execute command */ res = TPM_GetTestResult(&outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_SetOwnerInstall(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; BOOL state; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_BOOL(&ptr, &len, &state) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SetOwnerInstall(state); } static TPM_RESULT execute_TPM_OwnerSetDisable(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; BOOL disableState; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_BOOL(&ptr, &len, &disableState) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_OwnerSetDisable(disableState, &req->auth1); } static TPM_RESULT execute_TPM_PhysicalEnable(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_PhysicalEnable(); } static TPM_RESULT execute_TPM_PhysicalDisable(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_PhysicalDisable(); } static TPM_RESULT execute_TPM_PhysicalSetDeactivated(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; BOOL state; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_BOOL(&ptr, &len, &state) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_PhysicalSetDeactivated(state); } static TPM_RESULT execute_TPM_SetTempDeactivated(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ return TPM_SetTempDeactivated(&req->auth1); } static TPM_RESULT execute_TPM_SetOperatorAuth(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_SECRET operatorAuth; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_SECRET(&ptr, &len, &operatorAuth) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SetOperatorAuth(&operatorAuth); } static TPM_RESULT execute_TPM_TakeOwnership(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PROTOCOL_ID protocolID; UINT32 encOwnerAuthSize; BYTE *encOwnerAuth; UINT32 encSrkAuthSize; BYTE *encSrkAuth; TPM_KEY srkParams; TPM_KEY srkPub; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PROTOCOL_ID(&ptr, &len, &protocolID) || tpm_unmarshal_UINT32(&ptr, &len, &encOwnerAuthSize) || tpm_unmarshal_BLOB(&ptr, &len, &encOwnerAuth, encOwnerAuthSize) || tpm_unmarshal_UINT32(&ptr, &len, &encSrkAuthSize) || tpm_unmarshal_BLOB(&ptr, &len, &encSrkAuth, encSrkAuthSize) || tpm_unmarshal_TPM_KEY(&ptr, &len, &srkParams) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_TakeOwnership(protocolID, encOwnerAuthSize, encOwnerAuth, encSrkAuthSize, encSrkAuth, &srkParams, &req->auth1, &srkPub); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_KEY(srkPub); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY(&ptr, &len, &srkPub)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_KEY(srkPub); return res; } static TPM_RESULT execute_TPM_OwnerClear(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ return TPM_OwnerClear(&req->auth1); } static TPM_RESULT execute_TPM_ForceClear(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_ForceClear(); } static TPM_RESULT execute_TPM_DisableOwnerClear(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ return TPM_DisableOwnerClear(&req->auth1); } static TPM_RESULT execute_TPM_DisableForceClear(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_DisableForceClear(); } static TPM_RESULT execute_TSC_PhysicalPresence(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PHYSICAL_PRESENCE physicalPresence; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PHYSICAL_PRESENCE(&ptr, &len, &physicalPresence) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TSC_PhysicalPresence(physicalPresence); } static TPM_RESULT execute_TSC_ResetEstablishmentBit(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TSC_ResetEstablishmentBit(); } static TPM_RESULT execute_TPM_GetCapability(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_CAPABILITY_AREA capArea; UINT32 subCapSize; BYTE *subCap; UINT32 respSize; BYTE *resp = NULL; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_CAPABILITY_AREA(&ptr, &len, &capArea) || tpm_unmarshal_UINT32(&ptr, &len, &subCapSize) || tpm_unmarshal_BLOB(&ptr, &len, &subCap, subCapSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ #ifdef MTM_EMULATOR res = MTM_GetCapability(capArea, subCapSize, subCap, &respSize, &resp); #else res = TPM_GetCapability(capArea, subCapSize, subCap, &respSize, &resp); #endif if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + respSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, respSize) || tpm_marshal_BLOB(&ptr, &len, resp, respSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(resp); return res; } static TPM_RESULT execute_TPM_SetCapability(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_CAPABILITY_AREA capArea; UINT32 subCapSize, setValueSize; BYTE *subCap, *setValue; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_CAPABILITY_AREA(&ptr, &len, &capArea) || tpm_unmarshal_UINT32(&ptr, &len, &subCapSize) || tpm_unmarshal_BLOB(&ptr, &len, &subCap, subCapSize) || tpm_unmarshal_UINT32(&ptr, &len, &setValueSize) || tpm_unmarshal_BLOB(&ptr, &len, &setValue, setValueSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SetCapability(capArea, subCapSize, subCap, setValueSize, setValue, &req->auth1); } static TPM_RESULT execute_TPM_GetCapabilityOwner(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 non_volatile_flags, volatile_flags; TPM_VERSION version; BYTE *resp = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ res = TPM_GetCapabilityOwner(&req->auth1, &version, &non_volatile_flags, &volatile_flags); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 12; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_VERSION(&ptr, &len, &version) || tpm_marshal_UINT32(&ptr, &len, non_volatile_flags) || tpm_marshal_UINT32(&ptr, &len, volatile_flags)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(resp); return res; } static TPM_RESULT execute_TPM_GetAuditDigest(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 startOrdinal; TPM_COUNTER_VALUE counterValue; TPM_DIGEST auditDigest; BOOL more; UINT32 ordSize; UINT32 *ordList = NULL; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &startOrdinal) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_GetAuditDigest(startOrdinal, &counterValue, &auditDigest, &more, &ordSize, &ordList); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 10 + 20 + 1 + 4 + ordSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_COUNTER_VALUE(&ptr, &len, &counterValue) || tpm_marshal_TPM_DIGEST(&ptr, &len, &auditDigest) || tpm_marshal_BOOL(&ptr, &len, more) || tpm_marshal_UINT32(&ptr, &len, ordSize) || tpm_marshal_UINT32_ARRAY(&ptr, &len, ordList, ordSize/4)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(ordList); return res; } static TPM_RESULT execute_TPM_GetAuditDigestSigned(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; BOOL closeAudit; TPM_NONCE antiReplay; TPM_COUNTER_VALUE counterValue; TPM_DIGEST auditDigest; TPM_DIGEST ordinalDigest; UINT32 sigSize; BYTE *sig = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_BOOL(&ptr, &len, &closeAudit) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_GetAuditDigestSigned(keyHandle, closeAudit, &antiReplay, &req->auth1, &counterValue, &auditDigest, &ordinalDigest, &sigSize, &sig); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 10 + 20 + 20 + 4 + sigSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_COUNTER_VALUE(&ptr, &len, &counterValue) || tpm_marshal_TPM_DIGEST(&ptr, &len, &auditDigest) || tpm_marshal_TPM_DIGEST(&ptr, &len, &ordinalDigest) || tpm_marshal_UINT32(&ptr, &len, sigSize) || tpm_marshal_BLOB(&ptr, &len, sig, sigSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(sig); return res; } static TPM_RESULT execute_TPM_SetOrdinalAuditStatus(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_COMMAND_CODE ordinalToAudit; BOOL auditState; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_COMMAND_CODE(&ptr, &len, &ordinalToAudit) || tpm_unmarshal_BOOL(&ptr, &len, &auditState) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SetOrdinalAuditStatus(ordinalToAudit, auditState, &req->auth1); } static TPM_RESULT execute_TPM_FieldUpgrade(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_FieldUpgrade(); } static TPM_RESULT execute_TPM_SetRedirection(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_REDIR_COMMAND redirCmd; UINT32 inputDataSize; BYTE *inputData; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_REDIR_COMMAND(&ptr, &len, &redirCmd) || tpm_unmarshal_UINT32(&ptr, &len, &inputDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inputData, inputDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SetRedirection(keyHandle, redirCmd, inputDataSize, inputData, &req->auth1); } static TPM_RESULT execute_TPM_ResetLockValue(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ return TPM_ResetLockValue(&req->auth1); } static TPM_RESULT execute_TPM_Seal(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_ENCAUTH encAuth; UINT32 pcrInfoSize; TPM_PCR_INFO pcrInfo; UINT32 inDataSize; BYTE *inData; TPM_STORED_DATA sealedData; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &encAuth) || tpm_unmarshal_UINT32(&ptr, &len, &pcrInfoSize) || (pcrInfoSize > 0 && tpm_unmarshal_TPM_PCR_INFO(&ptr, &len, &pcrInfo)) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inData, inDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Seal(keyHandle, &encAuth, pcrInfoSize, &pcrInfo, inDataSize, inData, &req->auth1, &sealedData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_STORED_DATA(sealedData); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_STORED_DATA(&ptr, &len, &sealedData)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_STORED_DATA(sealedData); return res; } static TPM_RESULT execute_TPM_Unseal(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_STORED_DATA inData; UINT32 sealedDataSize; BYTE *secret = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_STORED_DATA(&ptr, &len, &inData) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Unseal(parentHandle, &inData, &req->auth1, &req->auth2, &sealedDataSize, &secret); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + sealedDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, sealedDataSize) || tpm_marshal_BLOB(&ptr, &len, secret, sealedDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(secret); return res; } static TPM_RESULT execute_TPM_UnBind(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; UINT32 inDataSize; BYTE *inData; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inData, inDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_UnBind(keyHandle, inDataSize, inData, &req->auth1, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_CreateWrapKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_ENCAUTH dataUsageAuth; TPM_ENCAUTH dataMigrationAuth; TPM_KEY keyInfo; TPM_KEY wrappedKey; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &dataUsageAuth) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &dataMigrationAuth) || tpm_unmarshal_TPM_KEY(&ptr, &len, &keyInfo) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CreateWrapKey(parentHandle, &dataUsageAuth, &dataMigrationAuth, &keyInfo, &req->auth1, &wrappedKey); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_KEY(wrappedKey); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY(&ptr, &len, &wrappedKey)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_KEY(wrappedKey); return res; } static TPM_RESULT execute_TPM_LoadKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_KEY inKey; TPM_KEY_HANDLE inkeyHandle; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_KEY(&ptr, &len, &inKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_LoadKey(parentHandle, &inKey, &req->auth1, &inkeyHandle); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY_HANDLE(&ptr, &len, inkeyHandle)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_LoadKey2(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_KEY inKey; TPM_KEY_HANDLE inkeyHandle; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_KEY(&ptr, &len, &inKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_LoadKey2(parentHandle, &inKey, &req->auth1, &inkeyHandle); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY_HANDLE(&ptr, &len, inkeyHandle)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_GetPubKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_PUBKEY pubKey; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_GetPubKey(keyHandle, &req->auth1, &pubKey); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PUBKEY(pubKey); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, &pubKey)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_PUBKEY(pubKey); return res; } static TPM_RESULT execute_TPM_Sealx(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_ENCAUTH encAuth; UINT32 pcrInfoSize; TPM_PCR_INFO pcrInfo; UINT32 inDataSize; BYTE *inData; TPM_STORED_DATA sealedData; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &encAuth) || tpm_unmarshal_UINT32(&ptr, &len, &pcrInfoSize) || (pcrInfoSize > 0 && tpm_unmarshal_TPM_PCR_INFO(&ptr, &len, &pcrInfo)) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inData, inDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Sealx(keyHandle, &encAuth, pcrInfoSize, &pcrInfo, inDataSize, inData, &req->auth1, &sealedData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_STORED_DATA(sealedData); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_STORED_DATA(&ptr, &len, &sealedData)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_STORED_DATA(sealedData); return res; } static TPM_RESULT execute_TPM_CreateMigrationBlob(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_MIGRATE_SCHEME migrationType; TPM_MIGRATIONKEYAUTH migrationKeyAuth; UINT32 encDataSize; BYTE *encData; UINT32 randomSize; BYTE *random = NULL; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_MIGRATE_SCHEME(&ptr, &len, &migrationType) || tpm_unmarshal_TPM_MIGRATIONKEYAUTH(&ptr, &len, &migrationKeyAuth) || tpm_unmarshal_UINT32(&ptr, &len, &encDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &encData, encDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CreateMigrationBlob(parentHandle, migrationType, &migrationKeyAuth, encDataSize, encData, &req->auth1, &req->auth2, &randomSize, &random, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + randomSize + 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, randomSize) || tpm_marshal_BLOB(&ptr, &len, random, randomSize) || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(random); tpm_free(outData); return res; } static TPM_RESULT execute_TPM_ConvertMigrationBlob(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; UINT32 inDataSize; BYTE *inData; UINT32 randomSize; BYTE *random; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inData, inDataSize) || tpm_unmarshal_UINT32(&ptr, &len, &randomSize) || tpm_unmarshal_BLOB(&ptr, &len, &random, randomSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ConvertMigrationBlob(parentHandle, inDataSize, inData, randomSize, random, &req->auth1, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_AuthorizeMigrationKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_MIGRATE_SCHEME migrateScheme; TPM_PUBKEY migrationKey; TPM_MIGRATIONKEYAUTH outData; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_MIGRATE_SCHEME(&ptr, &len, &migrateScheme) || tpm_unmarshal_TPM_PUBKEY(&ptr, &len, &migrationKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_AuthorizeMigrationKey(migrateScheme, &migrationKey, &req->auth1, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_MIGRATIONKEYAUTH(outData); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_MIGRATIONKEYAUTH(&ptr, &len, &outData)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_MIGRATIONKEYAUTH(outData); return res; } static TPM_RESULT execute_TPM_MigrateKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE maKeyHandle; TPM_PUBKEY pubKey; UINT32 inDataSize; BYTE *inData; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &maKeyHandle) || tpm_unmarshal_TPM_PUBKEY(&ptr, &len, &pubKey) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inData, inDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_MigrateKey(maKeyHandle, &pubKey, inDataSize, inData, &req->auth1, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_CMK_SetRestrictions(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_CMK_DELEGATE restriction; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_CMK_DELEGATE(&ptr, &len, &restriction) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_CMK_SetRestrictions(restriction, &req->auth1); } static TPM_RESULT execute_TPM_CMK_ApproveMA(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_DIGEST migrationAuthorityDigest; TPM_HMAC outData; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_DIGEST(&ptr, &len, &migrationAuthorityDigest) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CMK_ApproveMA(&migrationAuthorityDigest, &req->auth1, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_HMAC(&ptr, &len, &outData)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_CMK_CreateKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_ENCAUTH dataUsageAuth; TPM_KEY keyInfo; TPM_HMAC migrationAuthorityApproval; TPM_DIGEST migrationAuthorityDigest; TPM_KEY wrappedKey; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &dataUsageAuth) || tpm_unmarshal_TPM_KEY(&ptr, &len, &keyInfo) || tpm_unmarshal_TPM_HMAC(&ptr, &len, &migrationAuthorityApproval) || tpm_unmarshal_TPM_DIGEST(&ptr, &len, &migrationAuthorityDigest) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CMK_CreateKey(parentHandle, &dataUsageAuth, &keyInfo, &migrationAuthorityApproval, &migrationAuthorityDigest, &req->auth1, &req->auth2, &wrappedKey); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_KEY(wrappedKey); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY(&ptr, &len, &wrappedKey)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_KEY(wrappedKey); return res; } static TPM_RESULT execute_TPM_CMK_CreateTicket(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PUBKEY verificationKey; TPM_DIGEST signedData; UINT32 signatureValueSize; BYTE *signatureValue; TPM_DIGEST sigTicket; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PUBKEY(&ptr, &len, &verificationKey) || tpm_unmarshal_TPM_DIGEST(&ptr, &len, &signedData) || tpm_unmarshal_UINT32(&ptr, &len, &signatureValueSize) || tpm_unmarshal_BLOB(&ptr, &len, &signatureValue, signatureValueSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CMK_CreateTicket(&verificationKey, &signedData, signatureValueSize, signatureValue, &req->auth1, &sigTicket); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_DIGEST(&ptr, &len, &sigTicket)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_CMK_CreateBlob(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_MIGRATE_SCHEME migrationType; TPM_MIGRATIONKEYAUTH migrationKeyAuth; TPM_DIGEST pubSourceKeyDigest; UINT32 msaListSize; TPM_MSA_COMPOSITE msaList; UINT32 restrictTicketSize; TPM_CMK_AUTH restrictTicket; UINT32 sigTicketSize; TPM_HMAC sigTicket; UINT32 encDataSize; BYTE *encData; UINT32 randomSize; BYTE *random = NULL; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_MIGRATE_SCHEME(&ptr, &len, &migrationType) || tpm_unmarshal_TPM_MIGRATIONKEYAUTH(&ptr, &len, &migrationKeyAuth) || tpm_unmarshal_TPM_DIGEST(&ptr, &len, &pubSourceKeyDigest) || tpm_unmarshal_UINT32(&ptr, &len, &msaListSize) || tpm_unmarshal_TPM_MSA_COMPOSITE(&ptr, &len, &msaList) || tpm_unmarshal_UINT32(&ptr, &len, &restrictTicketSize) || (restrictTicketSize > 0 && tpm_unmarshal_TPM_CMK_AUTH(&ptr, &len, &restrictTicket)) || tpm_unmarshal_UINT32(&ptr, &len, &sigTicketSize) || (sigTicketSize > 0 && tpm_unmarshal_TPM_HMAC(&ptr, &len, &sigTicket)) || tpm_unmarshal_UINT32(&ptr, &len, &encDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &encData, encDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CMK_CreateBlob(parentHandle, migrationType, &migrationKeyAuth, &pubSourceKeyDigest, &msaList, restrictTicketSize > 0 ? &restrictTicket : NULL, sigTicketSize > 0 ? &sigTicket : NULL, encDataSize, encData, &req->auth1, &randomSize, &random, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + randomSize + 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, randomSize) || tpm_marshal_BLOB(&ptr, &len, random, randomSize) || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(random); tpm_free(outData); return res; } static TPM_RESULT execute_TPM_CMK_ConvertMigration(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_CMK_AUTH restrictTicket; TPM_HMAC sigTicket; TPM_KEY migratedKey; UINT32 msaListSize; TPM_MSA_COMPOSITE msaList; UINT32 randomSize; BYTE *random; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_CMK_AUTH(&ptr, &len, &restrictTicket) || tpm_unmarshal_TPM_HMAC(&ptr, &len, &sigTicket) || tpm_unmarshal_TPM_KEY(&ptr, &len, &migratedKey) || tpm_unmarshal_UINT32(&ptr, &len, &msaListSize) || tpm_unmarshal_TPM_MSA_COMPOSITE(&ptr, &len, &msaList) || tpm_unmarshal_UINT32(&ptr, &len, &randomSize) || tpm_unmarshal_BLOB(&ptr, &len, &random, randomSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CMK_ConvertMigration(parentHandle, &restrictTicket, &sigTicket, &migratedKey, &msaList, randomSize, random, &req->auth1, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_CreateMaintenanceArchive(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; BOOL generateRandom; UINT32 randomSize; BYTE *random = NULL; UINT32 archiveSize; BYTE *archive = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_BOOL(&ptr, &len, &generateRandom) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CreateMaintenanceArchive(generateRandom, &req->auth1, &randomSize, &random, &archiveSize, &archive); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + randomSize + 4 + archiveSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, randomSize) || tpm_marshal_BLOB(&ptr, &len, random, randomSize) || tpm_marshal_UINT32(&ptr, &len, archiveSize) || tpm_marshal_BLOB(&ptr, &len, archive, archiveSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(random); tpm_free(archive); return res; } static TPM_RESULT execute_TPM_LoadMaintenanceArchive(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 archiveSize; BYTE *archive; UINT32 sigSize; BYTE *sig; UINT32 randomSize; BYTE *random; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &archiveSize) || tpm_unmarshal_BLOB(&ptr, &len, &archive, archiveSize) || tpm_unmarshal_UINT32(&ptr, &len, &sigSize) || tpm_unmarshal_BLOB(&ptr, &len, &sig, sigSize) || tpm_unmarshal_UINT32(&ptr, &len, &randomSize) || tpm_unmarshal_BLOB(&ptr, &len, &random, randomSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_LoadMaintenanceArchive(archiveSize, archive, sigSize, sig, randomSize, random, &req->auth1); } static TPM_RESULT execute_TPM_KillMaintenanceFeature(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ return TPM_KillMaintenanceFeature(&req->auth1); } static TPM_RESULT execute_TPM_LoadManuMaintPub(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NONCE antiReplay; TPM_PUBKEY pubKey; TPM_DIGEST checksum; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || tpm_unmarshal_TPM_PUBKEY(&ptr, &len, &pubKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_LoadManuMaintPub(&antiReplay, &pubKey, &checksum); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_DIGEST(&ptr, &len, &checksum)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_ReadManuMaintPub(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NONCE antiReplay; TPM_DIGEST checksum; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ReadManuMaintPub(&antiReplay, &checksum); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_DIGEST(&ptr, &len, &checksum)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_SHA1Start(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 maxNumBytes; TPM_RESULT res; /* execute command */ res = TPM_SHA1Start(&maxNumBytes); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, maxNumBytes)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_SHA1Update(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 numBytes; BYTE *hashData; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &numBytes) || tpm_unmarshal_BLOB(&ptr, &len, &hashData, numBytes) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SHA1Update(numBytes, hashData); } static TPM_RESULT execute_TPM_SHA1Complete(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 hashDataSize; BYTE *hashData; TPM_DIGEST hashValue; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &hashDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &hashData, hashDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_SHA1Complete(hashDataSize, hashData, &hashValue); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_DIGEST(&ptr, &len, &hashValue)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_SHA1CompleteExtend(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PCRINDEX pcrNum; UINT32 hashDataSize; BYTE *hashData; TPM_DIGEST hashValue; TPM_PCRVALUE outDigest; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PCRINDEX(&ptr, &len, &pcrNum) || tpm_unmarshal_UINT32(&ptr, &len, &hashDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &hashData, hashDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_SHA1CompleteExtend(pcrNum, hashDataSize, hashData, &hashValue, &outDigest); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_DIGEST(&ptr, &len, &hashValue) || tpm_marshal_TPM_PCRVALUE(&ptr, &len, &outDigest)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_Sign(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; UINT32 areaToSignSize; BYTE *areaToSign; UINT32 sigSize; BYTE *sig = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_UINT32(&ptr, &len, &areaToSignSize) || tpm_unmarshal_BLOB(&ptr, &len, &areaToSign, areaToSignSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Sign(keyHandle, areaToSignSize, areaToSign, &req->auth1, &sigSize, &sig); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + sigSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, sigSize) || tpm_marshal_BLOB(&ptr, &len, sig, sigSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(sig); return res; } static TPM_RESULT execute_TPM_GetRandom(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 bytesRequested; UINT32 randomBytesSize; BYTE *randomBytes = NULL; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &bytesRequested) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_GetRandom(bytesRequested, &randomBytesSize, &randomBytes); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + randomBytesSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, randomBytesSize) || tpm_marshal_BLOB(&ptr, &len, randomBytes, randomBytesSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(randomBytes); return res; } static TPM_RESULT execute_TPM_StirRandom(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 dataSize; BYTE *inData; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &dataSize) || tpm_unmarshal_BLOB(&ptr, &len, &inData, dataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_StirRandom(dataSize, inData); } static TPM_RESULT execute_TPM_CertifyKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE certHandle; TPM_KEY_HANDLE keyHandle; TPM_NONCE antiReplay; TPM_CERTIFY_INFO certifyInfo; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &certHandle) || tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CertifyKey(certHandle, keyHandle, &antiReplay, &req->auth1, &req->auth2, &certifyInfo, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_CERTIFY_INFO(certifyInfo) + 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CERTIFY_INFO(&ptr, &len, &certifyInfo) || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_CERTIFY_INFO(certifyInfo); tpm_free(outData); return res; } static TPM_RESULT execute_TPM_CertifyKey2(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_KEY_HANDLE certHandle; TPM_DIGEST migrationPubDigest; TPM_NONCE antiReplay; TPM_CERTIFY_INFO certifyInfo; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &certHandle) || tpm_unmarshal_TPM_DIGEST(&ptr, &len, &migrationPubDigest) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CertifyKey2(keyHandle, certHandle, &migrationPubDigest, &antiReplay, &req->auth1, &req->auth2, &certifyInfo, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_CERTIFY_INFO(certifyInfo) + 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CERTIFY_INFO(&ptr, &len, &certifyInfo) || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_CERTIFY_INFO(certifyInfo); tpm_free(outData); return res; } static TPM_RESULT execute_TPM_CreateEndorsementKeyPair(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NONCE antiReplay; TPM_KEY_PARMS keyInfo; TPM_PUBKEY pubEndorsementKey; TPM_DIGEST Checksum; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || tpm_unmarshal_TPM_KEY_PARMS(&ptr, &len, &keyInfo) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CreateEndorsementKeyPair(&antiReplay, &keyInfo, &pubEndorsementKey, &Checksum); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PUBKEY(pubEndorsementKey) + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, &pubEndorsementKey) || tpm_marshal_TPM_DIGEST(&ptr, &len, &Checksum)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_PUBKEY(pubEndorsementKey); return res; } static TPM_RESULT execute_TPM_CreateRevocableEK(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NONCE antiReplay; TPM_KEY_PARMS keyInfo; BOOL generateReset; TPM_NONCE inputEKreset; TPM_PUBKEY pubEndorsementKey; TPM_DIGEST Checksum; TPM_NONCE outputEKreset; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || tpm_unmarshal_TPM_KEY_PARMS(&ptr, &len, &keyInfo) || tpm_unmarshal_BOOL(&ptr, &len, &generateReset) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &inputEKreset) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CreateRevocableEK(&antiReplay, &keyInfo, generateReset, &inputEKreset, &pubEndorsementKey, &Checksum, &outputEKreset); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PUBKEY(pubEndorsementKey) + 20 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, &pubEndorsementKey) || tpm_marshal_TPM_DIGEST(&ptr, &len, &Checksum) || tpm_marshal_TPM_NONCE(&ptr, &len, &outputEKreset)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_PUBKEY(pubEndorsementKey); return res; } static TPM_RESULT execute_TPM_RevokeTrust(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NONCE EKReset; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &EKReset) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_RevokeTrust(&EKReset); } static TPM_RESULT execute_TPM_ReadPubek(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NONCE antiReplay; TPM_PUBKEY pubEndorsementKey; TPM_DIGEST checksum; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ReadPubek(&antiReplay, &pubEndorsementKey, &checksum); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PUBKEY(pubEndorsementKey) + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, &pubEndorsementKey) || tpm_marshal_TPM_DIGEST(&ptr, &len, &checksum)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_PUBKEY(pubEndorsementKey); return res; } static TPM_RESULT execute_TPM_DisablePubekRead(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ return TPM_DisablePubekRead(&req->auth1); } static TPM_RESULT execute_TPM_OwnerReadInternalPub(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_PUBKEY publicPortion; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_OwnerReadInternalPub(keyHandle, &req->auth1, &publicPortion); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PUBKEY(publicPortion); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, &publicPortion)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_PUBKEY(publicPortion); return res; } static TPM_RESULT execute_TPM_MakeIdentity(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_ENCAUTH identityAuth; TPM_CHOSENID_HASH labelPrivCADigest; TPM_KEY idKeyParams; TPM_KEY idKey; UINT32 identityBindingSize; BYTE *identityBinding = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &identityAuth) || tpm_unmarshal_TPM_CHOSENID_HASH(&ptr, &len, &labelPrivCADigest) || tpm_unmarshal_TPM_KEY(&ptr, &len, &idKeyParams) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_MakeIdentity(&identityAuth, &labelPrivCADigest, &idKeyParams, &req->auth1, &req->auth2, &idKey, &identityBindingSize, &identityBinding); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_KEY(idKey) + 4 + identityBindingSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY(&ptr, &len, &idKey) || tpm_marshal_UINT32(&ptr, &len, identityBindingSize) || tpm_marshal_BLOB(&ptr, &len, identityBinding, identityBindingSize)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_KEY(idKey); tpm_free(identityBinding); return res; } static TPM_RESULT execute_TPM_ActivateIdentity(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE idKeyHandle; UINT32 blobSize; BYTE *blob; TPM_SYMMETRIC_KEY symmetricKey; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &idKeyHandle) || tpm_unmarshal_UINT32(&ptr, &len, &blobSize) || tpm_unmarshal_BLOB(&ptr, &len, &blob, blobSize) || len != 0) return TPM_BAD_PARAMETER; /* allocate memory for the symmetricKey data */ symmetricKey.size = blobSize; symmetricKey.data = tpm_malloc(blobSize); if (symmetricKey.data == NULL) return TPM_NOSPACE; /* execute command */ res = TPM_ActivateIdentity(idKeyHandle, blobSize, blob, &req->auth1, &req->auth2, &symmetricKey); if (res != TPM_SUCCESS) { free_TPM_SYMMETRIC_KEY(symmetricKey); return res; } /* marshal output */ rsp->paramSize = len = sizeof_TPM_SYMMETRIC_KEY(symmetricKey); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL) res = TPM_NOSPACE; else if (tpm_marshal_TPM_SYMMETRIC_KEY(&ptr, &len, &symmetricKey)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_SYMMETRIC_KEY(symmetricKey); return res; } static TPM_RESULT execute_TPM_Extend(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PCRINDEX pcrNum; TPM_DIGEST inDigest; TPM_PCRVALUE outDigest; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PCRINDEX(&ptr, &len, &pcrNum) || tpm_unmarshal_TPM_DIGEST(&ptr, &len, &inDigest) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ #ifdef MTM_EMULATOR res = MTM_Extend(pcrNum, &inDigest, &outDigest); #else res = TPM_Extend(pcrNum, &inDigest, &outDigest); #endif if (res != TPM_SUCCESS) return res; /* 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; } static TPM_RESULT execute_TPM_PCRRead(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PCRINDEX pcrIndex; TPM_PCRVALUE outDigest; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PCRINDEX(&ptr, &len, &pcrIndex) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_PCRRead(pcrIndex, &outDigest); if (res != TPM_SUCCESS) return res; /* 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; } static TPM_RESULT execute_TPM_Quote(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_NONCE extrnalData; TPM_PCR_SELECTION targetPCR; TPM_PCR_COMPOSITE pcrData; UINT32 sigSize; BYTE *sig = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &extrnalData) || tpm_unmarshal_TPM_PCR_SELECTION(&ptr, &len, &targetPCR) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Quote(keyHandle, &extrnalData, &targetPCR, &req->auth1, &pcrData, &sigSize, &sig); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PCR_COMPOSITE(pcrData) + 4 + sigSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PCR_COMPOSITE(&ptr, &len, &pcrData) || tpm_marshal_UINT32(&ptr, &len, sigSize) || tpm_marshal_BLOB(&ptr, &len, sig, sigSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(sig); return res; } static TPM_RESULT execute_TPM_PCR_Reset(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PCR_SELECTION pcrSelection; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PCR_SELECTION(&ptr, &len, &pcrSelection) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ #ifdef MTM_EMULATOR return MTM_PCR_Reset(&pcrSelection); #else return TPM_PCR_Reset(&pcrSelection); #endif } static TPM_RESULT execute_TPM_Quote2(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_NONCE externalData; TPM_PCR_SELECTION targetPCR; BOOL addVersion; TPM_PCR_INFO_SHORT pcrData; UINT32 versionInfoSize; TPM_CAP_VERSION_INFO versionInfo; UINT32 sigSize; BYTE *sig = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &externalData) || tpm_unmarshal_TPM_PCR_SELECTION(&ptr, &len, &targetPCR) || tpm_unmarshal_BOOL(&ptr, &len, &addVersion) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Quote2(keyHandle, &externalData, &targetPCR, addVersion, &req->auth1, &pcrData, &versionInfoSize, &versionInfo, &sigSize, &sig); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PCR_INFO_SHORT(pcrData) + 4 + versionInfoSize + 4 + sigSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PCR_INFO_SHORT(&ptr, &len, &pcrData) || tpm_marshal_UINT32(&ptr, &len, versionInfoSize) || ((addVersion == TRUE) && tpm_marshal_TPM_CAP_VERSION_INFO(&ptr, &len, &versionInfo)) || tpm_marshal_UINT32(&ptr, &len, sigSize) || tpm_marshal_BLOB(&ptr, &len, sig, sigSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(sig); return res; } static TPM_RESULT execute_TPM_ChangeAuth(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_PROTOCOL_ID protocolID; TPM_ENCAUTH newAuth; TPM_ENTITY_TYPE entityType; UINT32 encDataSize; BYTE *encData; UINT32 outDataSize; BYTE *outData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_PROTOCOL_ID(&ptr, &len, &protocolID) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &newAuth) || tpm_unmarshal_TPM_ENTITY_TYPE(&ptr, &len, &entityType) || tpm_unmarshal_UINT32(&ptr, &len, &encDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &encData, encDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ChangeAuth(parentHandle, protocolID, &newAuth, entityType, encDataSize, encData, &req->auth1, &req->auth2, &outDataSize, &outData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_ChangeAuthOwner(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PROTOCOL_ID protocolID; TPM_ENCAUTH newAuth; TPM_ENTITY_TYPE entityType; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_PROTOCOL_ID(&ptr, &len, &protocolID) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &newAuth) || tpm_unmarshal_TPM_ENTITY_TYPE(&ptr, &len, &entityType) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_ChangeAuthOwner(protocolID, &newAuth, entityType, &req->auth1); } static TPM_RESULT execute_TPM_OIAP(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_AUTHHANDLE authHandle; TPM_NONCE nonceEven; TPM_RESULT res; /* execute command */ res = TPM_OIAP(&authHandle, &nonceEven); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_AUTHHANDLE(&ptr, &len, authHandle) || tpm_marshal_TPM_NONCE(&ptr, &len, &nonceEven)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_OSAP(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_ENTITY_TYPE entityType; UINT32 entityValue; TPM_NONCE nonceOddOSAP; TPM_AUTHHANDLE authHandle; TPM_NONCE nonceEven; TPM_NONCE nonceEvenOSAP; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_ENTITY_TYPE(&ptr, &len, &entityType) || tpm_unmarshal_UINT32(&ptr, &len, &entityValue) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &nonceOddOSAP) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_OSAP(entityType, entityValue, &nonceOddOSAP, &authHandle, &nonceEven, &nonceEvenOSAP); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + 20 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_AUTHHANDLE(&ptr, &len, authHandle) || tpm_marshal_TPM_NONCE(&ptr, &len, &nonceEven) || tpm_marshal_TPM_NONCE(&ptr, &len, &nonceEvenOSAP)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_DSAP(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_ENTITY_TYPE entityType; TPM_KEY_HANDLE keyHandle; UINT32 entityValueSize; BYTE *entityValue; TPM_NONCE nonceOddDSAP; TPM_AUTHHANDLE authHandle; TPM_NONCE nonceEven; TPM_NONCE nonceEvenDSAP; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_ENTITY_TYPE(&ptr, &len, &entityType) || tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &nonceOddDSAP) || tpm_unmarshal_UINT32(&ptr, &len, &entityValueSize) || tpm_unmarshal_BLOB(&ptr, &len, &entityValue, entityValueSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_DSAP(entityType, keyHandle, &nonceOddDSAP, entityValueSize, entityValue, &authHandle, &nonceEven, &nonceEvenDSAP); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + 20 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_AUTHHANDLE(&ptr, &len, authHandle) || tpm_marshal_TPM_NONCE(&ptr, &len, &nonceEven) || tpm_marshal_TPM_NONCE(&ptr, &len, &nonceEvenDSAP)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_SetOwnerPointer(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_ENTITY_TYPE entityType; UINT32 entityValue; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_ENTITY_TYPE(&ptr, &len, &entityType) || tpm_unmarshal_UINT32(&ptr, &len, &entityValue) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_SetOwnerPointer(entityType, entityValue); } static TPM_RESULT execute_TPM_Delegate_Manage(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_FAMILY_ID familyID; TPM_FAMILY_OPERATION opFlag; UINT32 opDataSize; BYTE *opData; UINT32 retDataSize; BYTE *retData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_FAMILY_ID(&ptr, &len, &familyID) || tpm_unmarshal_TPM_FAMILY_OPERATION(&ptr, &len, &opFlag) || tpm_unmarshal_UINT32(&ptr, &len, &opDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &opData, opDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Delegate_Manage(familyID, opFlag, opDataSize, opData, &req->auth1, &retDataSize, &retData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + retDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, retDataSize) || tpm_marshal_BLOB(&ptr, &len, retData, retDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(retData); return res; } static TPM_RESULT execute_TPM_Delegate_CreateKeyDelegation(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_DELEGATE_PUBLIC publicInfo; TPM_ENCAUTH delAuth; UINT32 blobSize; TPM_DELEGATE_KEY_BLOB blob; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_DELEGATE_PUBLIC(&ptr, &len, &publicInfo) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &delAuth) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Delegate_CreateKeyDelegation(keyHandle, &publicInfo, &delAuth, &req->auth1, &blob); if (res != TPM_SUCCESS) return res; /* marshal output */ blobSize = sizeof_TPM_DELEGATE_KEY_BLOB(blob); rsp->paramSize = len = 4 + blobSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, blobSize) || tpm_marshal_TPM_DELEGATE_KEY_BLOB(&ptr, &len, &blob)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_DELEGATE_KEY_BLOB(blob); return res; } static TPM_RESULT execute_TPM_Delegate_CreateOwnerDelegation(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; BOOL increment; TPM_DELEGATE_PUBLIC publicInfo; TPM_ENCAUTH delAuth; UINT32 blobSize; TPM_DELEGATE_OWNER_BLOB blob; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_BOOL(&ptr, &len, &increment) || tpm_unmarshal_TPM_DELEGATE_PUBLIC(&ptr, &len, &publicInfo) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &delAuth) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Delegate_CreateOwnerDelegation(increment, &publicInfo, &delAuth, &req->auth1, &blob); if (res != TPM_SUCCESS) return res; /* marshal output */ blobSize = sizeof_TPM_DELEGATE_OWNER_BLOB(blob); rsp->paramSize = len = 4 + blobSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, blobSize) || tpm_marshal_TPM_DELEGATE_OWNER_BLOB(&ptr, &len, &blob)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_DELEGATE_OWNER_BLOB(blob); return res; } static TPM_RESULT execute_TPM_Delegate_LoadOwnerDelegation(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_DELEGATE_INDEX index; UINT32 blobSize; TPM_DELEGATE_OWNER_BLOB blob; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_DELEGATE_INDEX(&ptr, &len, &index) || tpm_unmarshal_UINT32(&ptr, &len, &blobSize) || tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(&ptr, &len, &blob) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_Delegate_LoadOwnerDelegation(index, &blob, &req->auth1); } static TPM_RESULT execute_TPM_Delegate_ReadTable(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 familyTableSize; BYTE *familyTable = NULL; UINT32 delegateTableSize; BYTE *delegateTable = NULL; TPM_RESULT res; /* execute command */ res = TPM_Delegate_ReadTable(&familyTableSize, &familyTable, &delegateTableSize, &delegateTable); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + familyTableSize + 4 + delegateTableSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, familyTableSize) || tpm_marshal_BLOB(&ptr, &len, familyTable, familyTableSize) || tpm_marshal_UINT32(&ptr, &len, delegateTableSize) || tpm_marshal_BLOB(&ptr, &len, delegateTable, delegateTableSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(familyTable); tpm_free(delegateTable); return res; } static TPM_RESULT execute_TPM_Delegate_UpdateVerification(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 inputSize; BYTE *inputData; UINT32 outputSize; BYTE *outputData = NULL; 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, &inputSize) || tpm_unmarshal_BLOB(&ptr, &len, &inputData, inputSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_Delegate_UpdateVerification(inputSize, inputData, &req->auth1, &outputSize, &outputData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outputSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outputSize) || tpm_marshal_BLOB(&ptr, &len, outputData, outputSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outputData); return res; } static TPM_RESULT execute_TPM_Delegate_VerifyDelegation(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 delegateSize; BYTE *delegation; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &delegateSize) || tpm_unmarshal_BLOB(&ptr, &len, &delegation, delegateSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_Delegate_VerifyDelegation(delegateSize, delegation); } static TPM_RESULT execute_TPM_NV_DefineSpace(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NV_DATA_PUBLIC pubInfo; TPM_ENCAUTH encAuth; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NV_DATA_PUBLIC(&ptr, &len, &pubInfo) || tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &encAuth) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_NV_DefineSpace(&pubInfo, &encAuth, &req->auth1); } static TPM_RESULT execute_TPM_NV_WriteValue(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NV_INDEX nvIndex; UINT32 offset; UINT32 dataSize; BYTE *data; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NV_INDEX(&ptr, &len, &nvIndex) || tpm_unmarshal_UINT32(&ptr, &len, &offset) || tpm_unmarshal_UINT32(&ptr, &len, &dataSize) || tpm_unmarshal_BLOB(&ptr, &len, &data, dataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_NV_WriteValue(nvIndex, offset, dataSize, data, &req->auth1); } static TPM_RESULT execute_TPM_NV_WriteValueAuth(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NV_INDEX nvIndex; UINT32 offset; UINT32 dataSize; BYTE *data; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NV_INDEX(&ptr, &len, &nvIndex) || tpm_unmarshal_UINT32(&ptr, &len, &offset) || tpm_unmarshal_UINT32(&ptr, &len, &dataSize) || tpm_unmarshal_BLOB(&ptr, &len, &data, dataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_NV_WriteValueAuth(nvIndex, offset, dataSize, data, &req->auth1); } static TPM_RESULT execute_TPM_NV_ReadValue(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NV_INDEX nvIndex; UINT32 offset; UINT32 inDataSize; UINT32 outDataSize; BYTE *data = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NV_INDEX(&ptr, &len, &nvIndex) || tpm_unmarshal_UINT32(&ptr, &len, &offset) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_NV_ReadValue(nvIndex, offset, inDataSize, &req->auth1, &outDataSize, &data); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, data, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(data); return res; } static TPM_RESULT execute_TPM_NV_ReadValueAuth(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_NV_INDEX nvIndex; UINT32 offset; UINT32 inDataSize; UINT32 outDataSize; BYTE *data = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_NV_INDEX(&ptr, &len, &nvIndex) || tpm_unmarshal_UINT32(&ptr, &len, &offset) || tpm_unmarshal_UINT32(&ptr, &len, &inDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_NV_ReadValueAuth(nvIndex, offset, inDataSize, &req->auth1, &outDataSize, &data); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, data, outDataSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(data); return res; } static TPM_RESULT execute_TPM_KeyControlOwner(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_PUBKEY pubKey; UINT32 bitName; BOOL bitValue; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_PUBKEY(&ptr, &len, &pubKey) || tpm_unmarshal_UINT32(&ptr, &len, &bitName) || tpm_unmarshal_BOOL(&ptr, &len, &bitValue) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_KeyControlOwner(keyHandle, pubKey, bitName, bitValue, &req->auth1); } static TPM_RESULT execute_TPM_SaveContext(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_HANDLE handle; TPM_RESOURCE_TYPE resourceType; BYTE label[16]; UINT32 contextSize; TPM_CONTEXT_BLOB contextBlob; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_HANDLE(&ptr, &len, &handle) || tpm_unmarshal_TPM_RESOURCE_TYPE(&ptr, &len, &resourceType) || tpm_unmarshal_BYTE_ARRAY(&ptr, &len, label, 16) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_SaveContext(handle, resourceType, label, &contextSize, &contextBlob); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + contextSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, contextSize) || tpm_marshal_TPM_CONTEXT_BLOB(&ptr, &len, &contextBlob)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_CONTEXT_BLOB(contextBlob); return res; } static TPM_RESULT execute_TPM_LoadContext(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_HANDLE entityHandle; BOOL keepHandle; UINT32 contextSize; TPM_CONTEXT_BLOB contextBlob; TPM_HANDLE handle; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_HANDLE(&ptr, &len, &entityHandle) || tpm_unmarshal_BOOL(&ptr, &len, &keepHandle) || tpm_unmarshal_UINT32(&ptr, &len, &contextSize) || tpm_unmarshal_TPM_CONTEXT_BLOB(&ptr, &len, &contextBlob) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_LoadContext(entityHandle, keepHandle, contextSize, &contextBlob, &handle); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_HANDLE(&ptr, &len, handle)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_FlushSpecific(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_HANDLE handle; TPM_RESOURCE_TYPE resourceType; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_HANDLE(&ptr, &len, &handle) || tpm_unmarshal_TPM_RESOURCE_TYPE(&ptr, &len, &resourceType) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ #ifdef MTM_EMULATOR return MTM_FlushSpecific(handle, resourceType); #else return TPM_FlushSpecific(handle, resourceType); #endif } static TPM_RESULT execute_TPM_GetTicks(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_CURRENT_TICKS currentTime; TPM_RESULT res; /* execute command */ res = TPM_GetTicks(¤tTime); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 32; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, ¤tTime)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_TickStampBlob(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; TPM_NONCE antiReplay; TPM_DIGEST digestToStamp; TPM_CURRENT_TICKS currentTicks; UINT32 sigSize; BYTE *sig = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || tpm_unmarshal_TPM_DIGEST(&ptr, &len, &digestToStamp) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_TickStampBlob(keyHandle, &antiReplay, &digestToStamp, &req->auth1, ¤tTicks, &sigSize, &sig); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 32 + 4 + sigSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, ¤tTicks) || tpm_marshal_UINT32(&ptr, &len, sigSize) || tpm_marshal_BLOB(&ptr, &len, sig, sigSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(sig); return res; } static TPM_RESULT execute_TPM_EstablishTransport(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE encHandle; TPM_TRANSPORT_PUBLIC transPublic; UINT32 secretSize; BYTE *secret; TPM_TRANSHANDLE transHandle; TPM_MODIFIER_INDICATOR locality; TPM_CURRENT_TICKS currentTicks; TPM_NONCE transNonce; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &encHandle) || tpm_unmarshal_TPM_TRANSPORT_PUBLIC(&ptr, &len, &transPublic) || tpm_unmarshal_UINT32(&ptr, &len, &secretSize) || tpm_unmarshal_BLOB(&ptr, &len, &secret, secretSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_EstablishTransport(encHandle, &transPublic, secretSize, secret, &req->auth1, &transHandle, &locality, ¤tTicks, &transNonce); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + 4 + 32 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_TRANSHANDLE(&ptr, &len, transHandle) || tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, locality) || tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, ¤tTicks) || tpm_marshal_TPM_NONCE(&ptr, &len, &transNonce)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_ExecuteTransport(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 inWrappedCmdSize; BYTE *inWrappedCmd; UINT64 currentTicks; TPM_MODIFIER_INDICATOR locality; UINT32 outWrappedCmdSize; BYTE *outWrappedCmd = NULL; 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, &inWrappedCmdSize) || tpm_unmarshal_BLOB(&ptr, &len, &inWrappedCmd, inWrappedCmdSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ExecuteTransport(inWrappedCmdSize, inWrappedCmd, &req->auth1, ¤tTicks, &locality, &outWrappedCmdSize, &outWrappedCmd); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 8 + 4 + 4 + outWrappedCmdSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT64(&ptr, &len, currentTicks) || tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, locality) || tpm_marshal_UINT32(&ptr, &len, outWrappedCmdSize) || tpm_marshal_BLOB(&ptr, &len, outWrappedCmd, outWrappedCmdSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outWrappedCmd); return res; } static TPM_RESULT execute_TPM_ReleaseTransportSigned(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE key; TPM_NONCE antiReplay; TPM_MODIFIER_INDICATOR locality; TPM_CURRENT_TICKS currentTicks; UINT32 signSize; BYTE *signature = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &key) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ReleaseTransportSigned(key, &antiReplay, &req->auth1, &req->auth2, &locality, ¤tTicks, &signSize, &signature); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + 32 + 4 + signSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, locality) || tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, ¤tTicks) || tpm_marshal_UINT32(&ptr, &len, signSize) || tpm_marshal_BLOB(&ptr, &len, signature, signSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(signature); return res; } static TPM_RESULT execute_TPM_CreateCounter(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_ENCAUTH authData; BYTE label[4]; TPM_COUNT_ID countID; TPM_COUNTER_VALUE counterValue; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_ENCAUTH(&ptr, &len, &authData) || tpm_unmarshal_BYTE_ARRAY(&ptr, &len, label, 4) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_CreateCounter(&authData, label, &req->auth1, &countID, &counterValue); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + sizeof_TPM_COUNTER_VALUE(counterValue); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_COUNT_ID(&ptr, &len, countID) || tpm_marshal_TPM_COUNTER_VALUE(&ptr, &len, &counterValue)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_IncrementCounter(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_COUNT_ID countID; TPM_COUNTER_VALUE count; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_COUNT_ID(&ptr, &len, &countID) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_IncrementCounter(countID, &req->auth1, &count); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 10; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_COUNTER_VALUE(&ptr, &len, &count)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_ReadCounter(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_COUNT_ID countID; TPM_COUNTER_VALUE count; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_COUNT_ID(&ptr, &len, &countID) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ReadCounter(countID, &count); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 10; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_COUNTER_VALUE(&ptr, &len, &count)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_ReleaseCounter(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_COUNT_ID countID; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_COUNT_ID(&ptr, &len, &countID) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ #ifdef MTM_EMULATOR return MTM_ReleaseCounter(countID, &req->auth1); #else return TPM_ReleaseCounter(countID, &req->auth1); #endif } static TPM_RESULT execute_TPM_ReleaseCounterOwner(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_COUNT_ID countID; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_COUNT_ID(&ptr, &len, &countID) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ #ifdef MTM_EMULATOR return MTM_ReleaseCounterOwner(countID, &req->auth1); #else return TPM_ReleaseCounterOwner(countID, &req->auth1); #endif } static TPM_RESULT execute_TPM_DAA_Join(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_HANDLE handle; BYTE stage; UINT32 inputSize0; BYTE *inputData0; UINT32 inputSize1; BYTE *inputData1; TPM_COMMAND_CODE ordinal; UINT32 outputSize; BYTE *outputData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_HANDLE(&ptr, &len, &handle) || tpm_unmarshal_BYTE(&ptr, &len, &stage) || tpm_unmarshal_UINT32(&ptr, &len, &inputSize0) || tpm_unmarshal_BLOB(&ptr, &len, &inputData0, inputSize0) || tpm_unmarshal_UINT32(&ptr, &len, &inputSize1) || tpm_unmarshal_BLOB(&ptr, &len, &inputData1, inputSize1) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_DAA_Join(handle, stage, inputSize0, inputData0, inputSize1, inputData1, &req->auth1, &ordinal, &outputSize, &outputData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outputSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outputSize) || tpm_marshal_BLOB(&ptr, &len, outputData, outputSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outputData); return res; } static TPM_RESULT execute_TPM_DAA_Sign(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_HANDLE handle; BYTE stage; UINT32 inputSize0; BYTE *inputData0; UINT32 inputSize1; BYTE *inputData1; TPM_COMMAND_CODE ordinal; UINT32 outputSize; BYTE *outputData = NULL; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_HANDLE(&ptr, &len, &handle) || tpm_unmarshal_BYTE(&ptr, &len, &stage) || tpm_unmarshal_UINT32(&ptr, &len, &inputSize0) || tpm_unmarshal_BLOB(&ptr, &len, &inputData0, inputSize0) || tpm_unmarshal_UINT32(&ptr, &len, &inputSize1) || tpm_unmarshal_BLOB(&ptr, &len, &inputData1, inputSize1) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_DAA_Sign(handle, stage, inputSize0, inputData0, inputSize1, inputData1, &req->auth1, &ordinal, &outputSize, &outputData); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outputSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outputSize) || tpm_marshal_BLOB(&ptr, &len, outputData, outputSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outputData); return res; } static TPM_RESULT execute_TPM_EvictKey(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE evictHandle; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &evictHandle) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_EvictKey(evictHandle); } static TPM_RESULT execute_TPM_Terminate_Handle(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_AUTHHANDLE handle; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_AUTHHANDLE(&ptr, &len, &handle) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_Terminate_Handle(handle); } static TPM_RESULT execute_TPM_SaveKeyContext(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE keyHandle; UINT32 keyContextSize; BYTE *keyContextBlob = NULL; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &keyHandle) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_SaveKeyContext(keyHandle, &keyContextSize, &keyContextBlob); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + keyContextSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, keyContextSize) || tpm_marshal_BLOB(&ptr, &len, keyContextBlob, keyContextSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(keyContextBlob); return res; } static TPM_RESULT execute_TPM_LoadKeyContext(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 keyContextSize; BYTE *keyContextBlob; TPM_KEY_HANDLE keyHandle; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &keyContextSize) || tpm_unmarshal_BLOB(&ptr, &len, &keyContextBlob, keyContextSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_LoadKeyContext(keyContextSize, keyContextBlob, &keyHandle); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY_HANDLE(&ptr, &len, keyHandle)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_SaveAuthContext(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_AUTHHANDLE authandle; UINT32 authContextSize; BYTE *authContextBlob = NULL; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_AUTHHANDLE(&ptr, &len, &authandle) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_SaveAuthContext(authandle, &authContextSize, &authContextBlob); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + authContextSize; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, authContextSize) || tpm_marshal_BLOB(&ptr, &len, authContextBlob, authContextSize)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(authContextBlob); return res; } static TPM_RESULT execute_TPM_LoadAuthContext(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; UINT32 authContextSize; BYTE *authContextBlob; TPM_KEY_HANDLE authHandle; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_UINT32(&ptr, &len, &authContextSize) || tpm_unmarshal_BLOB(&ptr, &len, &authContextBlob, authContextSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_LoadAuthContext(authContextSize, authContextBlob, &authHandle); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_KEY_HANDLE(&ptr, &len, authHandle)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_DirWriteAuth(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_DIRINDEX dirIndex; TPM_DIRVALUE newContents; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_DIRINDEX(&ptr, &len, &dirIndex) || tpm_unmarshal_TPM_DIRVALUE(&ptr, &len, &newContents) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ return TPM_DirWriteAuth(dirIndex, &newContents, &req->auth1); } static TPM_RESULT execute_TPM_DirRead(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_DIRINDEX dirIndex; TPM_DIRVALUE dirContents; TPM_RESULT res; /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_DIRINDEX(&ptr, &len, &dirIndex) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_DirRead(dirIndex, &dirContents); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_DIRVALUE(&ptr, &len, &dirContents)) { tpm_free(rsp->param); res = TPM_FAIL; } return res; } static TPM_RESULT execute_TPM_ChangeAuthAsymStart(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE idHandle; TPM_NONCE antiReplay; TPM_KEY_PARMS inTempKey; TPM_CERTIFY_INFO certifyInfo; UINT32 sigSize; BYTE *sig = NULL; TPM_KEY_HANDLE ephHandle; TPM_KEY outTempKey; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &idHandle) || tpm_unmarshal_TPM_NONCE(&ptr, &len, &antiReplay) || tpm_unmarshal_TPM_KEY_PARMS(&ptr, &len, &inTempKey) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ChangeAuthAsymStart(idHandle, &antiReplay, &inTempKey, &req->auth1, &certifyInfo, &sigSize, &sig, &ephHandle, &outTempKey); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 95 + 4 + sigSize + 4 + sizeof_TPM_KEY(outTempKey); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CERTIFY_INFO(&ptr, &len, &certifyInfo) || tpm_marshal_UINT32(&ptr, &len, sigSize) || tpm_marshal_BLOB(&ptr, &len, sig, sigSize) || tpm_marshal_TPM_KEY_HANDLE(&ptr, &len, ephHandle) || tpm_marshal_TPM_KEY(&ptr, &len, &outTempKey)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(sig); free_TPM_KEY(outTempKey); return res; } static TPM_RESULT execute_TPM_ChangeAuthAsymFinish(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_KEY_HANDLE parentHandle; TPM_KEY_HANDLE ephHandle; TPM_ENTITY_TYPE entityType; TPM_HMAC newAuthLink; UINT32 newAuthSize; BYTE *encNewAuth; UINT32 encDataSize; BYTE *encData; UINT32 outDataSize; BYTE *outData = NULL; TPM_NONCE saltNonce; TPM_DIGEST changeProof; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* unmarshal input */ ptr = req->param; len = req->paramSize; if (tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &parentHandle) || tpm_unmarshal_TPM_KEY_HANDLE(&ptr, &len, &ephHandle) || tpm_unmarshal_TPM_ENTITY_TYPE(&ptr, &len, &entityType) || tpm_unmarshal_TPM_HMAC(&ptr, &len, &newAuthLink) || tpm_unmarshal_UINT32(&ptr, &len, &newAuthSize) || tpm_unmarshal_BLOB(&ptr, &len, &encNewAuth, newAuthSize) || tpm_unmarshal_UINT32(&ptr, &len, &encDataSize) || tpm_unmarshal_BLOB(&ptr, &len, &encData, encDataSize) || len != 0) return TPM_BAD_PARAMETER; /* execute command */ res = TPM_ChangeAuthAsymFinish(parentHandle, ephHandle, entityType, &newAuthLink, newAuthSize, encNewAuth, encDataSize, encData, &req->auth1, &outDataSize, &outData, &saltNonce, &changeProof); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = 4 + outDataSize + 20 + 20; rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, outDataSize) || tpm_marshal_BLOB(&ptr, &len, outData, outDataSize) || tpm_marshal_TPM_NONCE(&ptr, &len, &saltNonce) || tpm_marshal_TPM_DIGEST(&ptr, &len, &changeProof)) { tpm_free(rsp->param); res = TPM_FAIL; } tpm_free(outData); return res; } static TPM_RESULT execute_TPM_Reset(TPM_REQUEST *req, TPM_RESPONSE *rsp) { /* execute command */ return TPM_Reset(); } static TPM_RESULT execute_TPM_OwnerReadPubek(TPM_REQUEST *req, TPM_RESPONSE *rsp) { BYTE *ptr; UINT32 len; TPM_PUBKEY pubEndorsementKey; TPM_RESULT res; /* compute parameter digest */ tpm_compute_in_param_digest(req); /* execute command */ res = TPM_OwnerReadPubek(&req->auth1, &pubEndorsementKey); if (res != TPM_SUCCESS) return res; /* marshal output */ rsp->paramSize = len = sizeof_TPM_PUBKEY(pubEndorsementKey); rsp->param = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, &pubEndorsementKey)) { tpm_free(rsp->param); res = TPM_FAIL; } free_TPM_PUBKEY(pubEndorsementKey); return res; } static void tpm_setup_rsp_auth(TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp) { tpm_hmac_ctx_t hmac; /* compute parameter digest */ if (ordinal != TPM_ORD_ExecuteTransport) tpm_compute_out_param_digest(ordinal, rsp); /* compute authorization values */ switch (rsp->tag) { case TPM_TAG_RSP_AUTH2_COMMAND: tpm_hmac_init(&hmac, rsp->auth2->secret, sizeof(rsp->auth2->secret)); tpm_hmac_update(&hmac, rsp->auth2->digest, sizeof(rsp->auth2->digest)); tpm_hmac_update(&hmac, rsp->auth2->nonceEven.nonce, sizeof(rsp->auth2->nonceEven.nonce)); tpm_hmac_update(&hmac, rsp->auth2->nonceOdd.nonce, sizeof(rsp->auth2->nonceOdd.nonce)); tpm_hmac_update(&hmac, (BYTE*)&rsp->auth2->continueAuthSession, 1); tpm_hmac_final(&hmac, rsp->auth2->auth); break; case TPM_TAG_RSP_AUTH1_COMMAND: tpm_hmac_init(&hmac, rsp->auth1->secret, sizeof(rsp->auth1->secret)); tpm_hmac_update(&hmac, rsp->auth1->digest, sizeof(rsp->auth1->digest)); tpm_hmac_update(&hmac, rsp->auth1->nonceEven.nonce, sizeof(rsp->auth1->nonceEven.nonce)); tpm_hmac_update(&hmac, rsp->auth1->nonceOdd.nonce, sizeof(rsp->auth1->nonceOdd.nonce)); tpm_hmac_update(&hmac, (BYTE*)&rsp->auth1->continueAuthSession, 1); tpm_hmac_final(&hmac, rsp->auth1->auth); break; } } static void tpm_setup_error_response(TPM_RESULT res, TPM_RESPONSE *rsp) { rsp->tag = TPM_TAG_RSP_COMMAND; rsp->size = 10; rsp->result = res; rsp->param = NULL; rsp->paramSize = 0; } static TPM_RESULT tpm_check_status_and_mode(TPM_REQUEST *req) { /* verify that self-test succeeded */ if (!tpmData.permanent.flags.selfTestSucceeded) return TPM_FAILEDSELFTEST; /* initialisation must be finished before we execute any command */ if (tpmData.stany.flags.postInitialise) return TPM_INVALID_POSTINIT; /* if the TPM is deactivated only a subset of all commands can be performed */ if ((tpmData.permanent.flags.deactivated || tpmData.stclear.flags.deactivated) && req->ordinal != TPM_ORD_Reset && req->ordinal != TPM_ORD_Init && req->ordinal != TPM_ORD_Startup && req->ordinal != TPM_ORD_SaveState && req->ordinal != TPM_ORD_SHA1Start && req->ordinal != TPM_ORD_SHA1Update && req->ordinal != TPM_ORD_SHA1Complete && req->ordinal != TPM_ORD_SHA1CompleteExtend && req->ordinal != TPM_ORD_OIAP && req->ordinal != TPM_ORD_OSAP && req->ordinal != TPM_ORD_DSAP && req->ordinal != TPM_ORD_GetCapability && req->ordinal != TPM_ORD_SetCapability && req->ordinal != TPM_ORD_TakeOwnership && req->ordinal != TPM_ORD_OwnerSetDisable && req->ordinal != TPM_ORD_PhysicalDisable && req->ordinal != TPM_ORD_PhysicalEnable && req->ordinal != TPM_ORD_PhysicalSetDeactivated && req->ordinal != TPM_ORD_ContinueSelfTest && req->ordinal != TPM_ORD_SelfTestFull && req->ordinal != TPM_ORD_GetTestResult && req->ordinal != TPM_ORD_FlushSpecific && req->ordinal != TPM_ORD_Terminate_Handle && req->ordinal != TPM_ORD_Extend && req->ordinal != TPM_ORD_PCR_Reset && req->ordinal != TPM_ORD_NV_DefineSpace && req->ordinal != TPM_ORD_NV_ReadValue && req->ordinal != TPM_ORD_NV_WriteValue && req->ordinal != TSC_ORD_PhysicalPresence && req->ordinal != TSC_ORD_ResetEstablishmentBit ) return TPM_DEACTIVATED; /* if the TPM is disabled only a subset of all commands can be performed */ if (tpmData.permanent.flags.disable && req->ordinal != TPM_ORD_Reset && req->ordinal != TPM_ORD_Init && req->ordinal != TPM_ORD_Startup && req->ordinal != TPM_ORD_SaveState && req->ordinal != TPM_ORD_SHA1Start && req->ordinal != TPM_ORD_SHA1Update && req->ordinal != TPM_ORD_SHA1Complete && req->ordinal != TPM_ORD_SHA1CompleteExtend && req->ordinal != TPM_ORD_OIAP && req->ordinal != TPM_ORD_OSAP && req->ordinal != TPM_ORD_DSAP && req->ordinal != TPM_ORD_GetCapability && req->ordinal != TPM_ORD_SetCapability && req->ordinal != TPM_ORD_OwnerSetDisable && req->ordinal != TPM_ORD_PhysicalEnable && req->ordinal != TPM_ORD_ContinueSelfTest && req->ordinal != TPM_ORD_SelfTestFull && req->ordinal != TPM_ORD_GetTestResult && req->ordinal != TPM_ORD_FlushSpecific && req->ordinal != TPM_ORD_Terminate_Handle && req->ordinal != TPM_ORD_Extend && req->ordinal != TPM_ORD_PCR_Reset && req->ordinal != TPM_ORD_NV_DefineSpace && req->ordinal != TPM_ORD_NV_ReadValue && req->ordinal != TPM_ORD_NV_WriteValue && req->ordinal != TSC_ORD_PhysicalPresence && req->ordinal != TSC_ORD_ResetEstablishmentBit ) return TPM_DISABLED; return TPM_SUCCESS; } void tpm_execute_command(TPM_REQUEST *req, TPM_RESPONSE *rsp) { TPM_RESULT res; /* setup authorisation as well as response tag and size */ memset(rsp, 0, sizeof(*rsp)); switch (req->tag) { case TPM_TAG_RQU_AUTH2_COMMAND: debug("[TPM_TAG_RQU_AUTH2_COMMAND]"); rsp->tag = TPM_TAG_RSP_AUTH2_COMMAND; rsp->size = 10 + 2 * 41; rsp->auth1 = &req->auth1; rsp->auth2 = &req->auth2; break; case TPM_TAG_RQU_AUTH1_COMMAND: debug("[TPM_TAG_RQU_AUTH1_COMMAND]"); rsp->tag = TPM_TAG_RSP_AUTH1_COMMAND; rsp->size = 10 + 41; rsp->auth1 = &req->auth1; break; case TPM_TAG_RQU_COMMAND: debug("[TPM_TAG_RQU_COMMAND]"); rsp->tag = TPM_TAG_RSP_COMMAND; rsp->size = 10; break; default: info("The tag value sent to for a command (0x%02x) is invalid", req->tag); tpm_setup_error_response(TPM_BADTAG, rsp); return; } /* check whether the command is allowed in the current mode of the TPM */ res = tpm_check_status_and_mode(req); if (res != TPM_SUCCESS) { info("tpm_check_status_and_mode(0x%02x) failed: (0x%02x) %s", req->ordinal, res, tpm_error_to_string(res)); tpm_setup_error_response(res, rsp); return; } /* handle command ordinal */ switch (req->ordinal) { case TPM_ORD_Startup: debug("[TPM_ORD_Startup]"); res = execute_TPM_Startup(req, rsp); break; case TPM_ORD_SaveState: debug("[TPM_ORD_SaveState]"); res = execute_TPM_SaveState(req, rsp); break; case TPM_ORD_SelfTestFull: debug("[TPM_ORD_SelfTestFull]"); res = execute_TPM_SelfTestFull(req, rsp); break; case TPM_ORD_ContinueSelfTest: debug("[TPM_ORD_ContinueSelfTest]"); res = execute_TPM_ContinueSelfTest(req, rsp); break; case TPM_ORD_GetTestResult: debug("[TPM_ORD_GetTestResult]"); res = execute_TPM_GetTestResult(req, rsp); break; case TPM_ORD_SetOwnerInstall: debug("[TPM_ORD_SetOwnerInstall]"); res = execute_TPM_SetOwnerInstall(req, rsp); break; case TPM_ORD_OwnerSetDisable: debug("[TPM_ORD_OwnerSetDisable]"); res = execute_TPM_OwnerSetDisable(req, rsp); break; case TPM_ORD_PhysicalEnable: debug("[TPM_ORD_PhysicalEnable]"); res = execute_TPM_PhysicalEnable(req, rsp); break; case TPM_ORD_PhysicalDisable: debug("[TPM_ORD_PhysicalDisable]"); res = execute_TPM_PhysicalDisable(req, rsp); break; case TPM_ORD_PhysicalSetDeactivated: debug("[TPM_ORD_PhysicalSetDeactivated]"); res = execute_TPM_PhysicalSetDeactivated(req, rsp); break; case TPM_ORD_SetTempDeactivated: debug("[TPM_ORD_SetTempDeactivated]"); res = execute_TPM_SetTempDeactivated(req, rsp); break; case TPM_ORD_SetOperatorAuth: debug("[TPM_ORD_SetOperatorAuth]"); res = execute_TPM_SetOperatorAuth(req, rsp); break; case TPM_ORD_TakeOwnership: debug("[TPM_ORD_TakeOwnership]"); res = execute_TPM_TakeOwnership(req, rsp); break; case TPM_ORD_OwnerClear: debug("[TPM_ORD_OwnerClear]"); res = execute_TPM_OwnerClear(req, rsp); break; case TPM_ORD_ForceClear: debug("[TPM_ORD_ForceClear]"); res = execute_TPM_ForceClear(req, rsp); break; case TPM_ORD_DisableOwnerClear: debug("[TPM_ORD_DisableOwnerClear]"); res = execute_TPM_DisableOwnerClear(req, rsp); break; case TPM_ORD_DisableForceClear: debug("[TPM_ORD_DisableForceClear]"); res = execute_TPM_DisableForceClear(req, rsp); break; case TSC_ORD_PhysicalPresence: res = execute_TSC_PhysicalPresence(req, rsp); break; case TSC_ORD_ResetEstablishmentBit: res = execute_TSC_ResetEstablishmentBit(req, rsp); break; case TPM_ORD_GetCapability: debug("[TPM_ORD_GetCapability]"); res = execute_TPM_GetCapability(req, rsp); break; case TPM_ORD_SetCapability: debug("[TPM_ORD_SetCapability]"); res = execute_TPM_SetCapability(req, rsp); break; case TPM_ORD_GetCapabilityOwner: debug("[TPM_ORD_GetCapabilityOwner]"); res = execute_TPM_GetCapabilityOwner(req, rsp); break; case TPM_ORD_GetAuditDigest: debug("[TPM_ORD_GetAuditDigest]"); res = execute_TPM_GetAuditDigest(req, rsp); break; case TPM_ORD_GetAuditDigestSigned: debug("[TPM_ORD_GetAuditDigestSigned]"); res = execute_TPM_GetAuditDigestSigned(req, rsp); break; case TPM_ORD_SetOrdinalAuditStatus: debug("[TPM_ORD_SetOrdinalAuditStatus]"); res = execute_TPM_SetOrdinalAuditStatus(req, rsp); break; case TPM_ORD_FieldUpgrade: debug("[TPM_ORD_FieldUpgrade]"); res = execute_TPM_FieldUpgrade(req, rsp); break; case TPM_ORD_SetRedirection: debug("[TPM_ORD_SetRedirection]"); res = execute_TPM_SetRedirection(req, rsp); break; case TPM_ORD_ResetLockValue: debug("[TPM_ORD_ResetLockValue]"); res = execute_TPM_ResetLockValue(req, rsp); break; case TPM_ORD_Seal: debug("[TPM_ORD_Seal]"); res = execute_TPM_Seal(req, rsp); break; case TPM_ORD_Unseal: debug("[TPM_ORD_Unseal]"); res = execute_TPM_Unseal(req, rsp); break; case TPM_ORD_UnBind: debug("[TPM_ORD_UnBind]"); res = execute_TPM_UnBind(req, rsp); break; case TPM_ORD_CreateWrapKey: debug("[TPM_ORD_CreateWrapKey]"); res = execute_TPM_CreateWrapKey(req, rsp); break; case TPM_ORD_LoadKey: debug("[TPM_ORD_LoadKey]"); res = execute_TPM_LoadKey(req, rsp); break; case TPM_ORD_LoadKey2: debug("[TPM_ORD_LoadKey2]"); res = execute_TPM_LoadKey2(req, rsp); break; case TPM_ORD_GetPubKey: debug("[TPM_ORD_GetPubKey]"); res = execute_TPM_GetPubKey(req, rsp); break; case TPM_ORD_Sealx: debug("[TPM_ORD_Sealx]"); res = execute_TPM_Sealx(req, rsp); break; case TPM_ORD_CreateMigrationBlob: debug("[TPM_ORD_CreateMigrationBlob]"); res = execute_TPM_CreateMigrationBlob(req, rsp); break; case TPM_ORD_ConvertMigrationBlob: debug("[TPM_ORD_ConvertMigrationBlob]"); res = execute_TPM_ConvertMigrationBlob(req, rsp); break; case TPM_ORD_AuthorizeMigrationKey: debug("[TPM_ORD_AuthorizeMigrationKey]"); res = execute_TPM_AuthorizeMigrationKey(req, rsp); break; case TPM_ORD_MigrateKey: debug("[TPM_ORD_MigrateKey]"); res = execute_TPM_MigrateKey(req, rsp); break; case TPM_ORD_CMK_SetRestrictions: debug("[TPM_ORD_CMK_SetRestrictions]"); res = execute_TPM_CMK_SetRestrictions(req, rsp); break; case TPM_ORD_CMK_ApproveMA: debug("[TPM_ORD_CMK_ApproveMA]"); res = execute_TPM_CMK_ApproveMA(req, rsp); break; case TPM_ORD_CMK_CreateKey: debug("[TPM_ORD_CMK_CreateKey]"); res = execute_TPM_CMK_CreateKey(req, rsp); break; case TPM_ORD_CMK_CreateTicket: debug("[TPM_ORD_CMK_CreateTicket]"); res = execute_TPM_CMK_CreateTicket(req, rsp); break; case TPM_ORD_CMK_CreateBlob: debug("[TPM_ORD_CMK_CreateBlob]"); res = execute_TPM_CMK_CreateBlob(req, rsp); break; case TPM_ORD_CMK_ConvertMigration: debug("[TPM_ORD_CMK_ConvertMigration]"); res = execute_TPM_CMK_ConvertMigration(req, rsp); break; case TPM_ORD_CreateMaintenanceArchive: debug("[TPM_ORD_CreateMaintenanceArchive]"); res = execute_TPM_CreateMaintenanceArchive(req, rsp); break; case TPM_ORD_LoadMaintenanceArchive: debug("[TPM_ORD_LoadMaintenanceArchive]"); res = execute_TPM_LoadMaintenanceArchive(req, rsp); break; case TPM_ORD_KillMaintenanceFeature: debug("[TPM_ORD_KillMaintenanceFeature]"); res = execute_TPM_KillMaintenanceFeature(req, rsp); break; case TPM_ORD_LoadManuMaintPub: debug("[TPM_ORD_LoadManuMaintPub]"); res = execute_TPM_LoadManuMaintPub(req, rsp); break; case TPM_ORD_ReadManuMaintPub: debug("[TPM_ORD_ReadManuMaintPub]"); res = execute_TPM_ReadManuMaintPub(req, rsp); break; case TPM_ORD_SHA1Start: debug("[TPM_ORD_SHA1Start]"); res = execute_TPM_SHA1Start(req, rsp); break; case TPM_ORD_SHA1Update: debug("[TPM_ORD_SHA1Update]"); res = execute_TPM_SHA1Update(req, rsp); break; case TPM_ORD_SHA1Complete: debug("[TPM_ORD_SHA1Complete]"); res = execute_TPM_SHA1Complete(req, rsp); break; case TPM_ORD_SHA1CompleteExtend: debug("[TPM_ORD_SHA1CompleteExtend]"); res = execute_TPM_SHA1CompleteExtend(req, rsp); break; case TPM_ORD_Sign: debug("[TPM_ORD_Sign]"); res = execute_TPM_Sign(req, rsp); break; case TPM_ORD_GetRandom: debug("[TPM_ORD_GetRandom]"); res = execute_TPM_GetRandom(req, rsp); break; case TPM_ORD_StirRandom: debug("[TPM_ORD_StirRandom]"); res = execute_TPM_StirRandom(req, rsp); break; case TPM_ORD_CertifyKey: debug("[TPM_ORD_CertifyKey]"); res = execute_TPM_CertifyKey(req, rsp); break; case TPM_ORD_CertifyKey2: debug("[TPM_ORD_CertifyKey2]"); res = execute_TPM_CertifyKey2(req, rsp); break; case TPM_ORD_CreateEndorsementKeyPair: debug("[TPM_ORD_CreateEndorsementKeyPair]"); res = execute_TPM_CreateEndorsementKeyPair(req, rsp); break; case TPM_ORD_CreateRevocableEK: debug("[TPM_ORD_CreateRevocableEK]"); res = execute_TPM_CreateRevocableEK(req, rsp); break; case TPM_ORD_RevokeTrust: debug("[TPM_ORD_RevokeTrust]"); res = execute_TPM_RevokeTrust(req, rsp); break; case TPM_ORD_ReadPubek: debug("[TPM_ORD_ReadPubek]"); res = execute_TPM_ReadPubek(req, rsp); break; case TPM_ORD_DisablePubekRead: debug("[TPM_ORD_DisablePubekRead]"); res = execute_TPM_DisablePubekRead(req, rsp); break; case TPM_ORD_OwnerReadInternalPub: debug("[TPM_ORD_OwnerReadInternalPub]"); res = execute_TPM_OwnerReadInternalPub(req, rsp); break; case TPM_ORD_MakeIdentity: debug("[TPM_ORD_MakeIdentity]"); res = execute_TPM_MakeIdentity(req, rsp); break; case TPM_ORD_ActivateIdentity: debug("[TPM_ORD_ActivateIdentity]"); res = execute_TPM_ActivateIdentity(req, rsp); break; case TPM_ORD_Extend: debug("[TPM_ORD_Extend]"); res = execute_TPM_Extend(req, rsp); break; case TPM_ORD_PCRRead: debug("[TPM_ORD_PCRRead]"); res = execute_TPM_PCRRead(req, rsp); break; case TPM_ORD_Quote: debug("[TPM_ORD_Quote]"); res = execute_TPM_Quote(req, rsp); break; case TPM_ORD_PCR_Reset: debug("[TPM_ORD_PCR_Reset]"); res = execute_TPM_PCR_Reset(req, rsp); break; case TPM_ORD_Quote2: debug("[TPM_ORD_Quote2]"); res = execute_TPM_Quote2(req, rsp); break; case TPM_ORD_ChangeAuth: debug("[TPM_ORD_ChangeAuth]"); res = execute_TPM_ChangeAuth(req, rsp); break; case TPM_ORD_ChangeAuthOwner: debug("[TPM_ORD_ChangeAuthOwner]"); res = execute_TPM_ChangeAuthOwner(req, rsp); break; case TPM_ORD_OIAP: debug("[TPM_ORD_OIAP]"); res = execute_TPM_OIAP(req, rsp); break; case TPM_ORD_OSAP: debug("[TPM_ORD_OSAP]"); res = execute_TPM_OSAP(req, rsp); break; case TPM_ORD_DSAP: debug("[TPM_ORD_DSAP]"); res = execute_TPM_DSAP(req, rsp); break; case TPM_ORD_SetOwnerPointer: debug("[TPM_ORD_SetOwnerPointer]"); res = execute_TPM_SetOwnerPointer(req, rsp); break; case TPM_ORD_Delegate_Manage: debug("[TPM_ORD_Delegate_Manage]"); res = execute_TPM_Delegate_Manage(req, rsp); break; case TPM_ORD_Delegate_CreateKeyDelegation: debug("[TPM_ORD_Delegate_CreateKeyDelegation]"); res = execute_TPM_Delegate_CreateKeyDelegation(req, rsp); break; case TPM_ORD_Delegate_CreateOwnerDelegation: debug("[TPM_ORD_Delegate_CreateOwnerDelegation]"); res = execute_TPM_Delegate_CreateOwnerDelegation(req, rsp); break; case TPM_ORD_Delegate_LoadOwnerDelegation: debug("[TPM_ORD_Delegate_LoadOwnerDelegation]"); res = execute_TPM_Delegate_LoadOwnerDelegation(req, rsp); break; case TPM_ORD_Delegate_ReadTable: debug("[TPM_ORD_Delegate_ReadTable]"); res = execute_TPM_Delegate_ReadTable(req, rsp); break; case TPM_ORD_Delegate_UpdateVerification: debug("[TPM_ORD_Delegate_UpdateVerification]"); res = execute_TPM_Delegate_UpdateVerification(req, rsp); break; case TPM_ORD_Delegate_VerifyDelegation: debug("[TPM_ORD_Delegate_VerifyDelegation]"); res = execute_TPM_Delegate_VerifyDelegation(req, rsp); break; case TPM_ORD_NV_DefineSpace: debug("[TPM_ORD_NV_DefineSpace]"); res = execute_TPM_NV_DefineSpace(req, rsp); break; case TPM_ORD_NV_WriteValue: debug("[TPM_ORD_NV_WriteValue]"); res = execute_TPM_NV_WriteValue(req, rsp); break; case TPM_ORD_NV_WriteValueAuth: debug("[TPM_ORD_NV_WriteValueAuth]"); res = execute_TPM_NV_WriteValueAuth(req, rsp); break; case TPM_ORD_NV_ReadValue: debug("[TPM_ORD_NV_ReadValue]"); res = execute_TPM_NV_ReadValue(req, rsp); break; case TPM_ORD_NV_ReadValueAuth: debug("[TPM_ORD_NV_ReadValueAuth]"); res = execute_TPM_NV_ReadValueAuth(req, rsp); break; case TPM_ORD_KeyControlOwner: debug("[TPM_ORD_KeyControlOwner]"); res = execute_TPM_KeyControlOwner(req, rsp); break; case TPM_ORD_SaveContext: debug("[TPM_ORD_SaveContext]"); res = execute_TPM_SaveContext(req, rsp); break; case TPM_ORD_LoadContext: debug("[TPM_ORD_LoadContext]"); res = execute_TPM_LoadContext(req, rsp); break; case TPM_ORD_FlushSpecific: debug("[TPM_ORD_FlushSpecific]"); res = execute_TPM_FlushSpecific(req, rsp); break; case TPM_ORD_GetTicks: debug("[TPM_ORD_GetTicks]"); res = execute_TPM_GetTicks(req, rsp); break; case TPM_ORD_TickStampBlob: debug("[TPM_ORD_TickStampBlob]"); res = execute_TPM_TickStampBlob(req, rsp); break; case TPM_ORD_EstablishTransport: debug("[TPM_ORD_EstablishTransport]"); res = execute_TPM_EstablishTransport(req, rsp); break; case TPM_ORD_ExecuteTransport: debug("[TPM_ORD_ExecuteTransport]"); res = execute_TPM_ExecuteTransport(req, rsp); break; case TPM_ORD_ReleaseTransportSigned: debug("[TPM_ORD_ReleaseTransportSigned]"); res = execute_TPM_ReleaseTransportSigned(req, rsp); break; case TPM_ORD_CreateCounter: debug("[TPM_ORD_CreateCounter]"); res = execute_TPM_CreateCounter(req, rsp); break; case TPM_ORD_IncrementCounter: debug("[TPM_ORD_IncrementCounter]"); res = execute_TPM_IncrementCounter(req, rsp); break; case TPM_ORD_ReadCounter: debug("[TPM_ORD_ReadCounter]"); res = execute_TPM_ReadCounter(req, rsp); break; case TPM_ORD_ReleaseCounter: debug("[TPM_ORD_ReleaseCounter]"); res = execute_TPM_ReleaseCounter(req, rsp); break; case TPM_ORD_ReleaseCounterOwner: debug("[TPM_ORD_ReleaseCounterOwner]"); res = execute_TPM_ReleaseCounterOwner(req, rsp); break; case TPM_ORD_DAA_Join: debug("[TPM_ORD_DAA_Join]"); res = execute_TPM_DAA_Join(req, rsp); break; case TPM_ORD_DAA_Sign: debug("[TPM_ORD_DAA_Sign]"); res = execute_TPM_DAA_Sign(req, rsp); break; case TPM_ORD_EvictKey: debug("[TPM_ORD_EvictKey]"); res = execute_TPM_EvictKey(req, rsp); break; case TPM_ORD_Terminate_Handle: debug("[TPM_ORD_Terminate_Handle]"); res = execute_TPM_Terminate_Handle(req, rsp); break; case TPM_ORD_SaveKeyContext: debug("[TPM_ORD_SaveKeyContext]"); res = execute_TPM_SaveKeyContext(req, rsp); break; case TPM_ORD_LoadKeyContext: debug("[TPM_ORD_LoadKeyContext]"); res = execute_TPM_LoadKeyContext(req, rsp); break; case TPM_ORD_SaveAuthContext: debug("[TPM_ORD_SaveAuthContext]"); res = execute_TPM_SaveAuthContext(req, rsp); break; case TPM_ORD_LoadAuthContext: debug("[TPM_ORD_LoadAuthContext]"); res = execute_TPM_LoadAuthContext(req, rsp); break; case TPM_ORD_DirWriteAuth: debug("[TPM_ORD_DirWriteAuth]"); res = execute_TPM_DirWriteAuth(req, rsp); break; case TPM_ORD_DirRead: debug("[TPM_ORD_DirRead]"); res = execute_TPM_DirRead(req, rsp); break; case TPM_ORD_ChangeAuthAsymStart: debug("[TPM_ORD_ChangeAuthAsymStart]"); res = execute_TPM_ChangeAuthAsymStart(req, rsp); break; case TPM_ORD_ChangeAuthAsymFinish: debug("[TPM_ORD_ChangeAuthAsymFinish]"); res = execute_TPM_ChangeAuthAsymFinish(req, rsp); break; case TPM_ORD_Reset: debug("[TPM_ORD_Reset]"); res = execute_TPM_Reset(req, rsp); break; case TPM_ORD_OwnerReadPubek: debug("[TPM_ORD_OwnerReadPubek]"); res = execute_TPM_OwnerReadPubek(req, rsp); break; default: #ifdef MTM_EMULATOR res = mtm_execute_command(req, rsp); if (res != TPM_BAD_ORDINAL) break; #endif info("The ordinal (0x%02x) was unknown or inconsistent", req->ordinal); tpm_setup_error_response(TPM_BAD_ORDINAL, rsp); return; } /* setup response */ if (res != TPM_SUCCESS) { info("TPM command failed: (0x%02x) %s", res, tpm_error_to_string(res)); tpm_setup_error_response(res, rsp); if (!(res & TPM_NON_FATAL)) { if (rsp->auth1 != NULL) rsp->auth1->continueAuthSession = FALSE; if (rsp->auth2 != NULL) rsp->auth2->continueAuthSession = FALSE; } } else { info("TPM command succeeded"); rsp->size += rsp->paramSize; if (rsp->tag != TPM_TAG_RSP_COMMAND) tpm_setup_rsp_auth(req->ordinal, rsp); if (tpmConf & TPM_CONF_STRONG_PERSISTENCE) { if (tpm_store_permanent_data() != 0) { error("tpm_store_permanent_data() failed"); } } } /* terminate authorization sessions if necessary */ if (rsp->auth1 != NULL && !rsp->auth1->continueAuthSession) TPM_FlushSpecific(rsp->auth1->authHandle, HANDLE_TO_RT(rsp->auth1->authHandle)); if (rsp->auth2 != NULL && !rsp->auth2->continueAuthSession) TPM_FlushSpecific(rsp->auth2->authHandle, TPM_RT_AUTH); /* if transportExclusive is set, only the execution of TPM_ExecuteTransport and TPM_ReleaseTransportSigned is allowed */ if (tpmData.stany.flags.transportExclusive && req->ordinal != TPM_ORD_ExecuteTransport && req->ordinal != TPM_ORD_ReleaseTransportSigned) { TPM_FlushSpecific(tpmData.stany.data.transExclusive, TPM_RT_TRANS); tpmData.stany.flags.transportExclusive = FALSE; } } int tpm_emulator_init(uint32_t startup, uint32_t conf) { /* initialize external functions and data */ if (tpm_extern_init() != 0) return -1; /* initialize the emulator */ debug("tpm_emulator_init(%d, 0x%08x)", startup, conf); tpmConf = conf; #ifdef MTM_EMULATOR info("MTM support enabled"); #endif /* try to restore data, if it fails use default values */ if (tpm_restore_permanent_data() != 0) tpm_init_data(); TPM_Init(startup); return 0; } void tpm_emulator_shutdown() { debug("tpm_emulator_shutdown()"); if (TPM_SaveState() != TPM_SUCCESS) { error("TPM_SaveState() failed"); } tpm_release_data(); /* release external functions and data */ tpm_extern_release(); } int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size) { TPM_REQUEST req; TPM_RESPONSE rsp; BYTE *ptr; UINT32 len; BOOL free_out; debug("tpm_handle_command()"); /* we need the whole packet at once, otherwise unmarshalling will fail */ if (tpm_unmarshal_TPM_REQUEST((uint8_t**)&in, &in_size, &req) != 0) { error("tpm_unmarshal_TPM_REQUEST() failed"); return -1; } /* update timing ticks */ tpm_update_ticks(); /* audit request */ tpm_audit_request(req.ordinal, &req); /* execute command */ tpm_execute_command(&req, &rsp); /* audit response */ tpm_audit_response(req.ordinal, &rsp); /* init output and marshal response */ if (*out != NULL) { if (*out_size < rsp.size) { error("output buffer to small (%d/%d)", *out_size, rsp.size); tpm_free(rsp.param); return -1; } *out_size = len = rsp.size; ptr = *out; free_out = FALSE; } else { *out_size = len = rsp.size; *out = ptr = tpm_malloc(len); if (ptr == NULL) { error("tpm_malloc() failed"); tpm_free(rsp.param); return -1; } free_out = TRUE; } if (tpm_marshal_TPM_RESPONSE(&ptr, &len, &rsp) != 0) { error("tpm_marshal_TPM_RESPONSE() failed"); if (free_out) tpm_free(*out); tpm_free(rsp.param); return -1; } tpm_free(rsp.param); return 0; } ================================================ FILE: tpm/tpm_commands.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_commands.h 452 2010-07-19 19:05:05Z mast $ */ #ifndef _TPM_COMMANDS_H_ #define _TPM_COMMANDS_H_ #include "tpm_structures.h" /* * The following commands are specified in * TPM Main Part 3 Commands [TPM_Part3]. */ /* * Admin Startup and State ([TPM_Part3], Section 3) * [tpm_startup.c] * This section describes the commands that start a TPM. */ /** * TPM_Init - initializes the TPM * @startupType: [in] Type of startup that is occurring * * Description: ([TPM_Part3], Section 3.1) * TPM_Init is a "physical" method of initializing a TPM, * there is no TPM_Init ordinal. */ void TPM_Init( TPM_STARTUP_TYPE startupType ); /** * TPM_Startup - starts the TPM * @startupType: [in] Type of startup that is occurring * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 3.2) * The TPM can startup in three different modes. (1) "clear" start where all * variables go back to their default or non-volatile set state. (2) "save" * start where the TPM recovers appropriate information and restores various * values based on a prior TPM_SaveState. (3) "deactivated" start where the * TPM turns itself off and requires another TPM_Init before the TPM will * execute in a fully operational state. */ TPM_RESULT TPM_Startup( TPM_STARTUP_TYPE startupType ); /** * TPM_SaveState - saves the current state of the TPM * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 3.3) * This warns a TPM to save some state information. If the relevant shielded * storage is non-volatile, this command need have no effect. If the relevant * shielded storage is volatile and the TPM alone is unable to detect the loss * of external power in time to move data to non-volatile memory, this command * should be presented before the systems enters a low or no power state. */ TPM_RESULT TPM_SaveState(void); /* * Admin Testing ([TPM_Part3], Section 4) * [tpm_testing.c] */ /** * TPM_SelfTestFull - tests all of the TPM capabilities * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 4.1) * Tests all of the TPM capabilities. */ TPM_RESULT TPM_SelfTestFull(void); /** * TPM_ContinueSelfTest - continues a started self test * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 4.2) * Informs the TPM that it may complete the self test of all TPM functions. */ TPM_RESULT TPM_ContinueSelfTest(void); /** * TPM_GetTestResult - provides the results of the self test * @outDataSize: [out] The size of the outData area * @outData: [out] The outData this is manufacturer specific * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 4.3) * TPM_GetTestResult provides manufacturer specific information regarding the * results of the self test. This command will also work when the TPM is in * self test failure mode. */ TPM_RESULT TPM_GetTestResult( UINT32 *outDataSize, BYTE **outData ); /* * Admin Opt-in ([TPM_Part3], Section 5) * [tpm_owner.c] */ /** * TPM_SetOwnerInstall - sets the persistent owner-install flag * @state: [in] State to which ownership flag is to be set * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.1) * When enabled but without an owner this command sets the persistent flag * that allows or disallows the ability to insert an owner. */ TPM_RESULT TPM_SetOwnerInstall( BOOL state ); /** * TPM_OwnerSetDisable - sets the persistent disable flag * @disableState: [in] Value for disable state, enable if TRUE * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.2) * The TPM owner sets the persistent disable flag. */ TPM_RESULT TPM_OwnerSetDisable( BOOL disableState, TPM_AUTH *auth1 ); /** * TPM_PhysicalEnable - sets the persistent disable flag to FALSE * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.3) * Sets the persistent disable flag to FALSE using physical presence as * authorization. */ TPM_RESULT TPM_PhysicalEnable(void); /** * TPM_PhysicalDisable - sets the persistent disable flag to TRUE * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.4) * Sets the persistent disable flag to TRUE using physical presence as * authorization. */ TPM_RESULT TPM_PhysicalDisable(void); /** * TPM_PhysicalSetDeactivated - sets the deactivated flag * @state: [in] State to which deactivated flag is to be set * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.5) * Sets the deactivated flag using physical presence as authorization. */ TPM_RESULT TPM_PhysicalSetDeactivated( BOOL state ); /** * TPM_SetTempDeactivated - deactivates the TPM until the next boot * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.6) * This command allows the operator of the platform to deactivate the TPM until * the next boot of the platform. The operator can provide the authorization by * either the assertion of physical presence or presenting the operation * authorization value. */ TPM_RESULT TPM_SetTempDeactivated( TPM_AUTH *auth1 ); /** * TPM_SetOperatorAuth - sets the operator authorization value * @operatorAuth: [in] The operator authorization * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.7) * This command allows the setting of the operator authorization value. There * is no confidentiality applied to the operator authorization as the value is * sent under the assumption of being local to the platform. */ TPM_RESULT TPM_SetOperatorAuth( TPM_SECRET *operatorAuth ); /* * Admin Ownership ([TPM_Part3], Section 6) * [tpm_owner.c] */ /** * TPM_TakeOwnership - inserts the TPM Ownership value into the TPM * @protocolID: [in] The ownership protocol in use * @encOwnerAuthSize: [in] The size of the encOwnerAuth field * @encOwnerAuth: [in] The owner authorization data encrypted with PUBEK * @encSrkAuthSize: [in] The size of the encSrkAuth field * @encSrkAuth: [in] The SRK authorization data encrypted with PUBEK * @srkParams: [in] All parameters of the new SRK * @auth1: [in, out] Authorization protocol parameters * @srkPub: [out] All parameters of the new SRK * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.1) * This command inserts the TPM Ownership value into the TPM. */ TPM_RESULT TPM_TakeOwnership( TPM_PROTOCOL_ID protocolID, UINT32 encOwnerAuthSize, BYTE *encOwnerAuth, UINT32 encSrkAuthSize, BYTE *encSrkAuth, TPM_KEY *srkParams, TPM_AUTH *auth1, TPM_KEY *srkPub ); /** * tpm_owner_clear - owner clear operation */ void tpm_owner_clear(void); /** * TPM_OwnerClear - performs the clear operation * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.2) * This command performs the clear operation under Owner authorization. It * is available until the Owner executes the DisableOwnerClear, at which * time any further invocation of this command returns TPM_CLEAR_DISABLED. */ TPM_RESULT TPM_OwnerClear( TPM_AUTH *auth1 ); /** * TPM_ForceClear - forces the clear operation * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.3) * This command performs the clear operation under physical access. It is * available until the execution of DisableForceClear, at which time any * further invocation of this command returns TPM_CLEAR_DISABLED. */ TPM_RESULT TPM_ForceClear(void); /** * TPM_DisableOwnerClear - disables the ability to execute TPM_OwnerClear * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.4) * This command disables the ability to execute the TPM_OwnerClear command * permanently. Once invoked the only method of clearing the TPM will require * physical access to the TPM. */ TPM_RESULT TPM_DisableOwnerClear( TPM_AUTH *auth1 ); /** * TPM_DisableForceClear - disables the ability to execute TPM_ForceClear * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.5) * The DisableForceClear command disables the execution of the ForceClear * command until the next startup cycle. Once this command is executed, * the TPM_ForceClear is disabled until another startup cycle is run. */ TPM_RESULT TPM_DisableForceClear(void); /** * TSC_PhysicalPresence - sets the physical presence flag * @physicalPresence: [in] The state to set the TPM's Physical Presence flags * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.6) * This command allows a process on the platform to indicate the assertion * of physical presence. */ TPM_RESULT TSC_PhysicalPresence( TPM_PHYSICAL_PRESENCE physicalPresence ); /** * TSC_ResetEstablishmentBit - resets the establishment bit * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 6.7) * The PC TPM Interface Specification (TIS) specifies a bit that is set upon * execution of the HASH_START sequence. This command allows for the resetting * of the bit under controlled circumstances. */ TPM_RESULT TSC_ResetEstablishmentBit(void); /* * The GetCapability Commands ([TPM_Part3], Section 7) * [tpm_capability.c] * The GetCapability command allows the TPM to report back to the requester * what type of TPM it is dealing with. The request for information requires * the requester to specify which piece of information that is required. */ /** * TPM_GetCapability - provides current information regarding the TPM * @capArea: [in] Partition of capabilities to be interrogated * @subCapSize: [in] Size of subCap parameter * @subCap: [in] Further definition of information * @respSize: [out] The length of the returned capability response * @resp: [out] The capability response * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 7.1) * This command provides current information regarding the TPM. */ TPM_RESULT TPM_GetCapability( TPM_CAPABILITY_AREA capArea, UINT32 subCapSize, BYTE *subCap, UINT32 *respSize, BYTE **resp ); /** * TPM_SetCapability - sets values in the TPM * @capArea: [in] Partition of capabilities to be set * @subCapSize: [in] Size of subCap parameter * @subCap: [in] Further definition of information * @setValueSize: [in] Size of the value to set * @setValue: [in] Value to set * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 7.2) * This command sets values in the TPM. */ TPM_RESULT TPM_SetCapability( TPM_CAPABILITY_AREA capArea, UINT32 subCapSize, BYTE *subCap, UINT32 setValueSize, BYTE *setValue, TPM_AUTH *auth1 ); /** * TPM_GetCapabilityOwner (deprecated) * @auth1: [in, out] Authorization protocol parameters * @version: [out] Properly filled out version structure * @non_volatile_flags: [out] Current state of the non-volatile flags * @volatile_flags: [out] Current state of the volatile flags * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 7.3) * This command is deprecated. */ TPM_RESULT TPM_GetCapabilityOwner( TPM_AUTH *auth1, TPM_VERSION *version, UINT32 *non_volatile_flags, UINT32 *volatile_flags ); /* * Auditing ([TPM_Part3], Section 8) * [tpm_audit.c] * The TPM generates an audit event in response to the TPM executing a * function that has the audit flag set to TRUE for that function. The * TPM maintains an extended value for all audited operations. */ /** * tpm_audit_request - audits a TPM request * @ordinal: [in] The ordinal of the request * @req: [in] The request to audit */ void tpm_audit_request( TPM_COMMAND_CODE ordinal, TPM_REQUEST *req ); /** * tpm_audit_response - audits a TPM response * @ordinal: [in] The ordinal of the response * @rsp: [in] The response to audit */ void tpm_audit_response( TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp ); /** * TPM_GetAuditDigest - provides the current audit digest * @startOrdinal: [in] The starting ordinal for the list of audited ordinals * @counterValue: [out] The current value of the audit monotonic counter * @auditDigest: [out] Log of all audited events * @more: [out] TRUE if the output does not contain all audited ordinals * @ordSize: [out] Size of the ordinal list in bytes * @ordList: [out] List of ordinals that are audited * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 8.3) * This provides the current audit digest. The external audit log has the * responsibility to track the parameters that constitute the audit digest. */ TPM_RESULT TPM_GetAuditDigest( UINT32 startOrdinal, TPM_COUNTER_VALUE *counterValue, TPM_DIGEST *auditDigest, BOOL *more, UINT32 *ordSize, UINT32 **ordList ); /** * TPM_GetAuditDigestSigned - provides the current (signed) audit digest * @keyHandle: [in] Handle of a loaded key that can perform digital signatures * @closeAudit: [in] Indication if audit session should be closed * @antiReplay: [in] A nonce to prevent replay attacks * @auth1: [in, out] Authorization protocol parameters * @counterValue: [out] The value of the audit monotonic counter * @auditDigest: [out] Log of all audited events * @ordinalDigest: [out] Digest of all audited ordinals * @sigSize: [out] The size of the sig parameter * @sig: [out] The signature of the area * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 8.4) * The signing of the audit log provides the entire digest value and the list * of currently audited commands. The inclusion of the list of audited commands * as an atomic operation is to tie the current digest value with the list of * commands that are being audited. */ TPM_RESULT TPM_GetAuditDigestSigned( TPM_KEY_HANDLE keyHandle, BOOL closeAudit, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_COUNTER_VALUE *counterValue, TPM_DIGEST *auditDigest, TPM_DIGEST *ordinalDigest, UINT32 *sigSize, BYTE **sig ); /** * TPM_SetOrdinalAuditStatus - set the audit flag for a given ordinal * @ordinalToAudit: [in] The ordinal whose audit flag is to be set * @auditState: [in] Value for audit flag * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 8.5) * Set the audit flag for a given ordinal. This command requires the * authorization of the TPM Owner. */ TPM_RESULT TPM_SetOrdinalAuditStatus( TPM_COMMAND_CODE ordinalToAudit, BOOL auditState, TPM_AUTH *auth1 ); /* * Administrative Functions ([TPM_Part3], Section 9) * [tpm_management.c] */ /** * TPM_FieldUpgrade - updates the protected capabilities * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 9.1) * This command provides a manufacturer specific method of updating * the protected capabilities */ TPM_RESULT TPM_FieldUpgrade(void); /** * TPM_SetRedirection - attaches a key to a redirection receiver * @keyHandle: [in] Handle of a loaded key that can implement redirection * @redirCmd: [in] The command to execute * @inputDataSize: [in] The size of the input data * @inputData: [in] Manufacturer parameter * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 9.2) */ TPM_RESULT TPM_SetRedirection( TPM_KEY_HANDLE keyHandle, TPM_REDIR_COMMAND redirCmd, UINT32 inputDataSize, BYTE *inputData, TPM_AUTH *auth1 ); /** * TPM_ResetLockValue - resets the TPM dictionary attack mitigation values * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 9.3) */ TPM_RESULT TPM_ResetLockValue( TPM_AUTH *auth1 ); /* * Storage functions ([TPM_Part3], Section 10) * [tpm_storage.c] */ /** * TPM_Seal - seals the TPM configuration * @keyHandle: [in] Handle of a loaded key that can perform seal operations * @encAuth: [in] The encrypted authorization data for the sealed data * @pcrInfoSize: [in] The size of the pcrInfo parameter * @pcrInfo: [in] The PCR selection information * @inDataSize: [in] The size of the inData parameter * @inData: [in] The data to be sealed to the platform and any specified PCRs * @auth1: [in, out] Authorization protocol parameters * @sealedData: [out] Encrypted, integrity-protected data object * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.1) * The Seal operation allows software to explicitly state the future trusted * configuration that the platform must be in for the secret to be revealed. */ TPM_RESULT TPM_Seal( TPM_KEY_HANDLE keyHandle, TPM_ENCAUTH *encAuth, UINT32 pcrInfoSize, TPM_PCR_INFO *pcrInfo, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, TPM_STORED_DATA *sealedData ); /** * TPM_Unseal - unseals the TPM configuration * @parentHandle: [in] Handle of a loaded key that can unseal the data * @inData: [in] The encrypted data generated by TPM_Seal * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @sealedDataSize: [out] The used size of the output area for secret * @secret: [out] Decrypted data that had been sealed * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.2) * The Unseal operation will reveal TPM_Sealed data only if it was encrypted * on this platform and the current configuration (as defined by the named PCR * contents) is the one named as qualified to decrypt it. */ TPM_RESULT TPM_Unseal( TPM_KEY_HANDLE parentHandle, TPM_STORED_DATA *inData, TPM_AUTH *auth1, TPM_AUTH *auth2, UINT32 *sealedDataSize, BYTE **secret ); /** * TPM_UnBind - decrypts the result of a TSS_Bind command * @keyHandle: [in] Handle of a loaded key that can perform UnBind operations * @inDataSize: [in] The size of the input blob * @inData: [in] Encrypted blob to be decrypted * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The length of the returned decrypted data * @outData: [out] The resulting decrypted data * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.3) * TPM_UnBind takes the data blob that is the result of a TSS_Bind command and * decrypts it for export to the User. The caller must authorize the use of the * key that will decrypt the incoming blob. UnBInd operates on a block-by-block * basis, and has no notion of any relation between one block and another. */ TPM_RESULT TPM_UnBind( TPM_KEY_HANDLE keyHandle, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData ); /** * TPM_CreateWrapKey - generates and creates a wrapped asymmetric key * @parentHandle: [in] Handle of a loaded key that can perform key wrapping * @dataUsageAuth: [in] Encrypted usage authorization data * @dataMigrationAuth: [in] Encrypted migration authorization data * @keyInfo: [in] Information about key to be created * @auth1: [in, out] Authorization protocol parameters * @wrappedKey: [out] The public and encrypted private key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.4) * The TPM_CreateWrapKey command both generates and creates a secure storage * bundle for asymmetric keys. The newly created key can be locked to a * specific PCR value by specifying a set of PCR registers. */ TPM_RESULT TPM_CreateWrapKey( TPM_KEY_HANDLE parentHandle, TPM_ENCAUTH *dataUsageAuth, TPM_ENCAUTH *dataMigrationAuth, TPM_KEY *keyInfo, TPM_AUTH *auth1, TPM_KEY *wrappedKey ); /** * TPM_LoadKey - loads a key into the TPM for further use * @parentHandle: [in] TPM handle of parent key * @inKey: [in] Incoming key structure, both private and public portions * @auth1: [in, out] Authorization protocol parameters * @inkeyHandle: [out] Internal TPM handle where decrypted key was loaded * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.5) * Before the TPM can use a key to either wrap, unwrap, bind, unbind, seal, * unseal, sign or perform any other action, it needs to be present in the * TPM. The TPM_LoadKey function loads the key into the TPM for further use. */ TPM_RESULT TPM_LoadKey( TPM_KEY_HANDLE parentHandle, TPM_KEY *inKey, TPM_AUTH *auth1, TPM_KEY_HANDLE *inkeyHandle ); /** * TPM_LoadKey2 - loads a key into the TPM for further use * @parentHandle: [in] TPM handle of parent key * @inKey: [in] Incoming key structure, both private and public portions * @auth1: [in, out] Authorization protocol parameters * @inkeyHandle: [out] Internal TPM handle where decrypted key was loaded * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.5) * Before the TPM can use a key to either wrap, unwrap, bind, unbind, seal, * unseal, sign or perform any other action, it needs to be present in the * TPM. The TPM_LoadKey function loads the key into the TPM for further use. */ TPM_RESULT TPM_LoadKey2( TPM_KEY_HANDLE parentHandle, TPM_KEY *inKey, TPM_AUTH *auth1, TPM_KEY_HANDLE *inkeyHandle ); /** * TPM_GetPubKey - provides the public key value from a loaded key * @keyHandle: [in] TPM handle of key * @auth1: [in, out] Authorization protocol parameters * @pubKey: [out] Public portion of key in keyHandle * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.6) * The owner of a key may wish to obtain the public key value from a loaded * key. This information may have privacy concerns so the command must have * authorization from the key owner. */ TPM_RESULT TPM_GetPubKey( TPM_KEY_HANDLE keyHandle, TPM_AUTH *auth1, TPM_PUBKEY *pubKey ); /** * TPM_Sealx - seals encrypted data to a TPM configuration * @keyHandle: [in] Handle of a loaded key that can perform seal operations * @encAuth: [in] The encrypted authorization data for the sealed data * @pcrInfoSize: [in] The size of the pcrInfo parameter * @pcrInfo: [in] The PCR selection information (MUST be TPM_PCR_INFO_LONG) * @inDataSize: [in] The size of the inData parameter * @inData: [in] The data to be sealed to the platform and any specified PCRs * @auth1: [in, out] Authorization protocol parameters * @sealedData: [out] Encrypted, integrity-protected data object * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 10.7) * The SEALX command works exactly like the SEAL command with the additional * requirement of encryption for the inData parameter. This command also * places in the sealed blob the information that the unseal also requires * encryption. */ TPM_RESULT TPM_Sealx( TPM_KEY_HANDLE keyHandle, TPM_ENCAUTH *encAuth, UINT32 pcrInfoSize, TPM_PCR_INFO *pcrInfo, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, TPM_STORED_DATA *sealedData ); /** * tpm_get_free_key - allocates a new key slot * Returns: the key handle on success, TPM_INVALID_HANDLE otherwise. */ TPM_KEY_HANDLE tpm_get_free_key(void); /** * tpm_encrypt_public - encrypts the input data with the specified public key * @key: [in], Public key * @in: [in] Input data to encrypt * @in_size: [in] Size of the input data * @enc: [out] Encrypted data * @enc_size: [out] Size of the encrypted data * Returns: 0 on success, -1 otherwise. */ int tpm_encrypt_public( TPM_PUBKEY_DATA *key, BYTE *in, UINT32 in_size, BYTE *enc, UINT32 *enc_size ); /** * tpm_encrypt_private - encrypts the input data with the specified private key * @key: [in], Private key * @in: [in] Input data to encrypt * @in_size: [in] Size of the input data * @enc: [out] Encrypted data * @enc_size: [out] Size of the encrypted data * Returns: 0 on success, -1 otherwise. */ int tpm_encrypt_private( TPM_KEY_DATA *key, BYTE *in, UINT32 in_size, BYTE *enc, UINT32 *enc_size ); /** * tpm_decrypt - decrypts the input data with the specified private key * @key: [in], Private key * @enc: [in] Encrypted data * @enc_size: [in] Size of the encrypted data * @out: [out] Decrypted data * @out_size: [out] Size of the decrypted data * Returns: 0 on success, -1 otherwise. */ int tpm_decrypt( TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, BYTE *out, UINT32 *out_size ); /** * tpm_encrypt_sealed_data - encrypts a TPM_SEALED_DATA structure * @key: [in], Private key * @seal: [in] Structure to encrypt * @enc: [out] Encrypted structure * @enc_size: [out] Size of the encrypted structure * Returns: 0 on success, -1 otherwise. */ int tpm_encrypt_sealed_data( TPM_KEY_DATA *key, TPM_SEALED_DATA *seal, BYTE *enc, UINT32 *enc_size ); /** * tpm_decrypt_sealed_data - decrypts a TPM_SEALED_DATA structure * @key: [in], Private key * @enc: [in] Encrypted structure * @enc_size: [in] Size of the encrypted structure * @seal: [out] Decrypted structure * @buf: [out] Buffer for the decrypted structure (to be freed by the caller) * Returns: 0 on success, -1 otherwise. */ int tpm_decrypt_sealed_data( TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, TPM_SEALED_DATA *seal, BYTE **buf ); /** * tpm_encrypt_sealed_data - encrypts a TPM_STORE_ASYMKEY structure * @key: [in], Private key * @store: [in] Structure to encrypt * @enc: [out] Encrypted structure * @enc_size: [out] Size of the encrypted structure * Returns: 0 on success, -1 otherwise. */ int tpm_encrypt_private_key( TPM_KEY_DATA *key, TPM_STORE_ASYMKEY *store, BYTE *enc, UINT32 *enc_size ); /** * tpm_decrypt_sealed_data - decrypts a TPM_STORE_ASYMKEY structure * @key: [in], Private key * @enc: [in] Encrypted structure * @enc_size: [in] Size of the encrypted structure * @store: [out] Decrypted structure * @buf: [out] Buffer for the decrypted structure (to be freed by the caller) * @buf_size: [out] Size of the buffer * Returns: 0 on success, -1 otherwise. */ int tpm_decrypt_private_key( TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, TPM_STORE_ASYMKEY *store, BYTE **buf, UINT32 *buf_size ); /** * tpm_compute_key_digest - computes the digest of a key * @key: [in] Key * @digest: [out] Digest of the key * @Returns: 0 on success, -1 otherwise. */ int tpm_compute_key_digest( TPM_KEY *key, TPM_DIGEST *digest ); /** * tpm_compute_key_data_digest - computes the digest of the public part of a key * @key: [in] Key * @digest: [out] Digest of the key * @Returns: 0 on success, -1 otherwise. */ int tpm_compute_key_data_digest( TPM_KEY_DATA *key, TPM_DIGEST *digest ); /** * tpm_compute_pubkey_checksum - computes the checksum of a public key * @antiReplay: [in] Nonce to prevent replay of messages * @pubKey: [in] Public key * @checksum: [out] Checksum of the public key and the nonce * @Returns: 0 on success, -1 otherwise. */ int tpm_compute_pubkey_checksum( TPM_NONCE *antiReplay, TPM_PUBKEY *pubKey, TPM_DIGEST *checksum ); /** * tpm_compute_pubkey_digest - computes the digest of a public key * @key: [in] Public key * @digest: [out] Digest of the key * @Returns: 0 on success, -1 otherwise. */ int tpm_compute_pubkey_digest( TPM_PUBKEY *key, TPM_DIGEST *digest ); /** * tpm_setup_key_parms - sets the key parameters according to the given key * @key: [in] Key * @params: [out] Key parameters to set * @Returns: 0 on success, -1 otherwise. */ int tpm_setup_key_parms( TPM_KEY_DATA *key, TPM_KEY_PARMS *parms ); /** * tpm_setup_pubkey_data - creates an internal public key based on the given key * @in: [in] Public Key of type TPM_PUBKEY * @out: [out] Internal public key of type TPM_PUBKEY_DATA * @Returns: 0 on success, -1 otherwise. */ int tpm_setup_pubkey_data( TPM_PUBKEY *in, TPM_PUBKEY_DATA *out ); /** * tpm_extract_pubkey - extracts the public part of the specified key * @in: [in] Key * @out: [out] Public key * @Returns: 0 on success, -1 otherwise. */ int tpm_extract_pubkey( TPM_KEY_DATA *key, TPM_PUBKEY *pubKey ); /** * tpm_extract_store_pubkey - extracts the public part of the specified key * @in: [in] Key * @out: [out] Public key * @Returns: 0 on success, -1 otherwise. */ int tpm_extract_store_pubkey( TPM_KEY_DATA *key, TPM_STORE_PUBKEY *pubKey ); /** * internal_TPM_LoadKey - loads the specified key into the TPM * @inKey: [in] Incoming key structure, both private and public portions * @inkeyHandle: [out] Internal TPM handle where decrypted key was loaded */ TPM_RESULT internal_TPM_LoadKey( TPM_KEY *inKey, TPM_KEY_HANDLE *inkeyHandle ); /* * Migration ([TPM_Part3], Section 11) * [tpm_migration.c] */ /** * TPM_CreateMigrationBlob - creates a migration blob * @parentHandle: [in] Handle of the parent key that can decrypt encData * @migrationType: [in] The migration type, either MIGRATE or REWRAP * @migrationKeyAuth: [in] Migration public key and its authorization digest * @encDataSize: [in] The size of the encData parameter * @encData: [in] The encrypted entity that is to be modified * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @randomSize: [out] The used size of the output area for random * @random: [out] String used for xor encryption * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The modified, encrypted entity * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.1) * The TPM_CreateMigrationBlob command implements the first step in the * process of moving a migratable key to a new parent or platform. */ 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_ConvertMigrationBlob - converts a migration into a wrapped blob * @parentHandle: [in] Handle of a loaded key that can decrypt keys * @inDataSize: [in] Size of inData * @inData: [in] The XOR d and encrypted key * @randomSize: [in] Size of random * @random: [in] Random value used to hide key data * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The encrypted private key that can be loaded with LoadKey * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.2) * This command takes a migration blob and creates a normal wrapped blob. * The migrated blob must be loaded into the TPM using the normal TPM_LoadKey * function. Note that the command migrates private keys, only. */ TPM_RESULT TPM_ConvertMigrationBlob( TPM_KEY_HANDLE parentHandle, UINT32 inDataSize, BYTE *inData, UINT32 randomSize, BYTE *random, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData ); /** * TPM_AuthorizeMigrationKey - creates an authorization blob * @migrateScheme: [in] Migration operation that is to be permitted for this key * @migrationKey: [in] The public key to be authorized * @auth1: [in, out] Authorization protocol parameters * @outData: [out] Returned public key and authorization digest * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.3) * This command creates an authorization blob, to allow the TPM owner to * specify which migration facility they will use and allow users to migrate * information without further involvement with the TPM owner. */ TPM_RESULT TPM_AuthorizeMigrationKey( TPM_MIGRATE_SCHEME migrateScheme, TPM_PUBKEY *migrationKey, TPM_AUTH *auth1, TPM_MIGRATIONKEYAUTH *outData ); /** * TPM_MigrateKey - performs the function of a migration authority * @maKeyHandle: [in] Handle of the key to be used to migrate the key * @pubKey: [in] Public key to which the blob is to be migrated * @inDataSize: [in] The size of inData * @inData: [in] The input blob * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The re-encrypted blob * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.4) */ TPM_RESULT TPM_MigrateKey( TPM_KEY_HANDLE maKeyHandle, TPM_PUBKEY *pubKey, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData ); /** * TPM_CMK_SetRestrictions - dictates the usage of a restricted migration key * @restriction: [in] The bit mask of how to set the restrictions on CMK keys * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.5) * This command is used by the Owner to dictate the usage of a restricted- * migration key with delegated authorisation (authorisation other than actual * Owner authorisation). */ TPM_RESULT TPM_CMK_SetRestrictions( TPM_CMK_DELEGATE restriction, TPM_AUTH *auth1 ); /** * TPM_CMK_ApproveMA - creates an authorization ticket * @migrationAuthorityDigest: [in] A digest of a TPM_MSA_COMPOSITE structure * @auth1: [in, out] Authorization protocol parameters * @outData: [out] HMAC of the migrationAuthorityDigest * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.6) */ TPM_RESULT TPM_CMK_ApproveMA( TPM_DIGEST *migrationAuthorityDigest, TPM_AUTH *auth1, TPM_HMAC *outData ); /** * TPM_CMK_CreateKey - generates and creates a wrapped CMK * @parentHandle: [in] Handle of a loaded key that can perform key wrapping * @dataUsageAuth: [in] Encrypted usage authorization data for the sealed data * @keyInfo: [in] Information about key to be created * @migrationAuthorityApproval: [in] A ticket created by the TPM owner * @migrationAuthorityDigest: [in] The digest of the public key of the MSA or MA * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @wrappedKey: [out] The public and encrypted private key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.7) * The TPM_CreateWrapRestrictedKey command both generates and creates a * secure storage bundle for asymmetric keys whose migration is controlled * by a migration authority. */ TPM_RESULT TPM_CMK_CreateKey( TPM_KEY_HANDLE parentHandle, TPM_ENCAUTH *dataUsageAuth, TPM_KEY *keyInfo, TPM_HMAC *migrationAuthorityApproval, TPM_DIGEST *migrationAuthorityDigest, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_KEY *wrappedKey ); /** * TPM_CMK_CreateTicket - creates a ticket for proving a signature verification * @verificationKey: [in] The public key to be used to check signatureValue * @signedData: [in] The data proported to be signed * @signatureValueSize: [in] The size of the signatureValue * @signatureValue: [in] The signatureValue to be verified * @auth1: [in, out] Authorization protocol parameters * @sigTicket: [out] Ticket that proves digest created on this TPM * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.8) * The TPM_verifySignature command uses a public key to verify the signature * over a digest. TPM_verifySignature provides a ticket that can be used to * prove to the same TPM that signature verification with a particular public * key was successful. */ TPM_RESULT TPM_CMK_CreateTicket( TPM_PUBKEY *verificationKey, TPM_DIGEST *signedData, UINT32 signatureValueSize, BYTE *signatureValue, TPM_AUTH *auth1, TPM_DIGEST *sigTicket ); /** * TPM_CMK_CreateBlob - creates a migration blob * @parentHandle: [in] Handle of the parent key that can decrypt encData * @migrationType: [in] The migration type * @migrationKeyAuth: [in] Migration public key and its authorization digest * @pubSourceKeyDigest: [in] Digest of the entity's public key to be migrated * @msaList: [in] Digests of public keys belonging to MAs * @restrictTicket: [in] The digests of the public keys * @sigTicket: [in] A signature ticket, generate by the TPM * @encDataSize: [in] The size of the encData parameter * @encData: [in] The encrypted entity that is to be modified * @auth1: [in, out] Authorization protocol parameters * @randomSize: [out] The used size of the output area for random * @random: [out] String used for xor encryption * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The modified, encrypted entity * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.9) * TPM_CMK_CreateBlob command is very similar to TPM_CreateMigrationBlob, * except that it (1) uses an extra ticket (restrictedKeyAuth) instead * of a migrationAuth authorization session; (2) uses the migration options * TPM_MS_RESTRICT_MIGRATE or TPM_MS_RESTRICT_APPROVE. */ TPM_RESULT TPM_CMK_CreateBlob( TPM_KEY_HANDLE parentHandle, TPM_MIGRATE_SCHEME migrationType, TPM_MIGRATIONKEYAUTH *migrationKeyAuth, TPM_DIGEST *pubSourceKeyDigest, TPM_MSA_COMPOSITE *msaList, TPM_CMK_AUTH *restrictTicket, TPM_HMAC *sigTicket, UINT32 encDataSize, BYTE *encData, TPM_AUTH *auth1, UINT32 *randomSize, BYTE **random, UINT32 *outDataSize, BYTE **outData ); /** * TPM_CMK_ConvertMigration - completes the migration of certified blobs * @parentHandle: [in] Handle of a loaded key that can decrypt keys * @restrictTicket: [in] The digests of the public keys * @sigTicket: [in] A signature ticket, generated by the TPM * @migratedKey: [in] The public key of the key to be migrated * @msaList: [in] One or more digests of public keys belonging to MAs * @randomSize: [in] Size of random * @random: [in] Random value used to hide key data * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The encrypted private key that can be loaded * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 11.10) */ TPM_RESULT TPM_CMK_ConvertMigration( TPM_KEY_HANDLE parentHandle, TPM_CMK_AUTH *restrictTicket, TPM_HMAC *sigTicket, TPM_KEY *migratedKey, TPM_MSA_COMPOSITE *msaList, UINT32 randomSize, BYTE *random, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData ); /* * Maintenance Functions ([TPM_Part3], Section 12) * [tpm_maintenance.c] */ /** * TPM_CreateMaintenanceArchive - creates the maintenance archive * @generateRandom: [in] Use RNG or Owner auth to generate random * @auth1: [in, out] Authorization protocol parameters * @randomSize: [out] Size of the returned random data * @random: [out] Random data to XOR with result * @archiveSize: [out] Size of the encrypted archive * @archive: [out] Encrypted key archive * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 12.1) * This command creates the maintenance archive. It can only be executed by * the owner, and may be shut off with the KillMaintenanceFeature command. */ TPM_RESULT TPM_CreateMaintenanceArchive( BOOL generateRandom, TPM_AUTH *auth1, UINT32 *randomSize, BYTE **random , UINT32 *archiveSize, BYTE **archive ); /** * TPM_LoadMaintenanceArchive - loads in a maintenance archive * @archiveSize: [in] Size of encrypted key archive * @archive: [in] Encrypted key archive * @sigSize: [in] Size of archive signature * @sig: [in] archive signature * @randomSize: [in] Size of the random data * @random: [in] Random data to XOR with encrypted archive * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 12.2) * This command loads in a maintenance archive that has been massaged * by the manufacturer to load into another TPM. */ TPM_RESULT TPM_LoadMaintenanceArchive( UINT32 archiveSize, BYTE *archive, UINT32 sigSize, BYTE *sig, UINT32 randomSize, BYTE *random, TPM_AUTH *auth1 ); /** * TPM_KillMaintenanceFeature - prevents the creation of a maintenance archive * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 12.3) * The KillMaintencanceFeature is a permanent action that prevents ANYONE from * creating a maintenance archive. This action, once taken, is permanent until * a new TPM Owner is set. This action is to allow those customers who do not * want the maintenance feature to prohibit it. */ TPM_RESULT TPM_KillMaintenanceFeature( TPM_AUTH *auth1 ); /** * TPM_LoadManuMaintPub - loads the manufacturer's public key * @antiReplay: [in] AntiReplay and validation nonce * @pubKey: [in] The public key of the manufacturer to be in use for maintenance * @checksum: [out] Digest of pubKey and antiReplay * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 12.4) * The LoadManuMaintPub command loads the manufacturer's public key for use in * the maintenance process. The command installs ManuMaintPub in persistent * data storage inside a TPM. */ TPM_RESULT TPM_LoadManuMaintPub( TPM_NONCE *antiReplay, TPM_PUBKEY *pubKey, TPM_DIGEST *checksum ); /** * TPM_ReadManuMaintPub - provides a digest of the manufacturer's public key * @antiReplay: [in] AntiReplay and validation nonce * @checksum: [out] Digest of pubKey and antiReplay * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 12.5) * The ReadManuMaintPub command is used to check whether the manufacturer's * public maintenance key in a TPM has the expected value. The command * provides a digest of the installed key, rather than the key itself. */ TPM_RESULT TPM_ReadManuMaintPub( TPM_NONCE *antiReplay, TPM_DIGEST *checksum ); /* * Cryptographic Functions ([TPM_Part3], Section 13) * [tpm_crypto.c] */ /** * TPM_SHA1Start - starts the process of calculating a SHA-1 digest * @maxNumBytes: [out] Maximum number of bytes that can be sent to SHA1Update * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.1) * This capability starts the process of calculating a SHA-1 digest. */ TPM_RESULT TPM_SHA1Start( UINT32 *maxNumBytes ); /** * TPM_SHA1Update - inputs blocks of data into a pending SHA-1 digest * @numBytes: [in] The number of bytes in hashData * @hashData: [in] Bytes to be hashed * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.2) * This capability inputs complete blocks of data into a pending SHA-1 digest. * At the end of the process, the digest remains pending. */ TPM_RESULT TPM_SHA1Update( UINT32 numBytes, BYTE *hashData ); /** * TPM_SHA1Complete - terminates a pending SHA-1 calculation * @hashDataSize: [in] Number of bytes in hashData, MUST be 64 or less * @hashData: [in] Final bytes to be hashed * @hashValue: [out] The output of the SHA-1 hash * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.3) * This capability terminates a pending SHA-1 calculation. */ TPM_RESULT TPM_SHA1Complete( UINT32 hashDataSize, BYTE *hashData, TPM_DIGEST *hashValue ); /** * TPM_SHA1CompleteExtend - terminates and extends a pending SHA-1 calculation * @pcrNum: [in] Index of the PCR to be modified * @hashDataSize: [in] Number of bytes in hashData, MUST be 64 or less * @hashData: [in] Final bytes to be hashed * @hashValue: [out] The output of the SHA-1 hash * @outDigest: [out] The PCR value after execution of the command * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.4) * This capability terminates a pending SHA-1 calculation and EXTENDS the * result into a Platform Configuration Register using a SHA-1 hash process. */ TPM_RESULT TPM_SHA1CompleteExtend( TPM_PCRINDEX pcrNum, UINT32 hashDataSize, BYTE *hashData, TPM_DIGEST *hashValue, TPM_PCRVALUE *outDigest ); /** * tpm_verify - verifies the signature with the specified key * @key: [in] key to verify the signature * @auth: [in, out] Authorization protocol parameters * @isInfo: [in] True if the input data is of type TPM_SIGN_INFO * @data: [in] The input data * @dataSize: [in] The size of the input data * @sig: [in] The digital signature * @sigSize: [in] The size of the digital signature * Returns: TPM_SUCCESS if the signature is valid, a TPM error code otherwise. */ TPM_RESULT tpm_verify( TPM_PUBKEY_DATA *key, TPM_AUTH *auth, BOOL isInfo, BYTE *data, UINT32 dataSize, BYTE *sig, UINT32 sigSize ); /** * tpm_sign - signs data with the specified key * @key: [in] key to compute the signature * @auth: [in, out] Authorization protocol parameters * @isInfo: [in] True if the input data is of type TPM_SIGN_INFO * @areaToSign: [in] The value to sign * @areaToSignSize: [in] The size of the areaToSign parameter * @sig: [out] The digital signature * @sigSize: [out] The size of the digital signature * Returns: TPM_SUCCESS if the signature is valid, a TPM error code otherwise. */ TPM_RESULT tpm_sign( TPM_KEY_DATA *key, TPM_AUTH *auth, BOOL isInfo, BYTE *areaToSign, UINT32 areaToSignSize, BYTE **sig, UINT32 *sigSize ); /** * TPM_Sign - signs data and provides the resulting digital signature * @keyHandle: [in] Handle of a loaded key that can perform digital signatures * @areaToSignSize: [in] The size of the areaToSign parameter * @areaToSign: [in] The value to sign * @auth1: [in, out] Authorization protocol parameters * @sigSize: [out] The length of the returned digital signature * @sig: [out] The resulting digital signature * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.5) * The Sign command signs data and provides the resulting digital signature. */ TPM_RESULT TPM_Sign( TPM_KEY_HANDLE keyHandle, UINT32 areaToSignSize, BYTE *areaToSign, TPM_AUTH *auth1, UINT32 *sigSize, BYTE **sig ); /** * tpm_get_random_bytes - provides the requested amount of random bytes * @buf: [out] buffer to fill with random data * @nbytes: [in] requested number of random bytes */ void tpm_get_random_bytes( void *buf, size_t nbytes ); /** * TPM_GetRandom - provides the next bytes from the RNG * @bytesRequested: [in] Number of bytes to return * @randomBytesSize: [out] The number of bytes returned * @randomBytes: [out] The returned bytes * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.6) * GetRandom provides the next bytesRequested bytes from the random number * generator to the caller. */ TPM_RESULT TPM_GetRandom( UINT32 bytesRequested, UINT32 *randomBytesSize, BYTE **randomBytes ); /** * TPM_StirRandom - adds entropy to the RNG state * @dataSize: [in] Number of bytes of input (256) * @inData: [in] Data to add entropy to RNG state * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.7) * StirRandom adds entropy to the RNG state. */ TPM_RESULT TPM_StirRandom( UINT32 dataSize, BYTE *inData ); /** * TPM_CertifyKey - certifies the public portion of a non-migratable key * @certHandle: [in] Handle of the key to be used to certify the key * @keyHandle: [in] Handle of the key to be certified * @antiReplay: [in] 160 bits of externally supplied data (typically a nonce) * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @certifyInfo: [out] Certify information relative to keyhandle * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The signed public key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.8) * The TPM_CERTIFYKEY operation allows a key to certify the public portion of * certain storage and signing keys. A TPM identity key may be used to certify * non-migratable keys but is not permitted to certify migratory keys. */ TPM_RESULT TPM_CertifyKey( TPM_KEY_HANDLE certHandle, TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_CERTIFY_INFO *certifyInfo, UINT32 *outDataSize, BYTE **outData ); /** * TPM_CertifyKey2 - certifies a CMK * @certHandle: [in] Handle of the key to be used to certify the key * @keyHandle: [in] Handle of the key to be certified * @migrationPubDigest: [in] Digest of the public key of a Migration Authority * @antiReplay: [in] 160 bits of externally supplied data (typically a nonce) * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @certifyInfo: [out] TPM_CERTIFY_INFO2 relative to keyHandle * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The signed public key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 13.9) * This command provides the ability to certify a Certifiable Migration Key * (CMK). This certification requires additional parameters and output then * the TPM_CertifyKey. This command always uses the TPM_SIGN_INFO2 structure. * All other aspects of the command are the same as TPM_CertifyKey. */ TPM_RESULT TPM_CertifyKey2( TPM_KEY_HANDLE certHandle, TPM_KEY_HANDLE keyHandle, TPM_DIGEST *migrationPubDigest, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_CERTIFY_INFO *certifyInfo, UINT32 *outDataSize, BYTE **outData ); /* * Credential Handling ([TPM_Part3], Section 14) * [tpm_credentials.c] * There are two create EK commands. The first matches the 1.1 functionality. * The second provides the mechanism to enable revokeEK and provides * FIPS 140-2 compatibility. */ /** * TPM_CreateEndorsementKeyPair - creates the TPM endorsement key * @antiReplay: [in] Arbitrary data * @keyInfo: [in] Information about key to be created * @pubEndorsementKey: [out] The public endorsement key * @Checksum: [out] Hash of pubEndorsementKey and antiReplay * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 14.1) * This command creates the TPM endorsement key. It returns a failure code if * an endorsement key already exists. */ TPM_RESULT TPM_CreateEndorsementKeyPair( TPM_NONCE *antiReplay, TPM_KEY_PARMS *keyInfo, TPM_PUBKEY *pubEndorsementKey, TPM_DIGEST *Checksum ); /** * TPM_CreateRevocableEK - creates the TPM endorsement key * @antiReplay: [in] Arbitrary data * @keyInfo: [in] Information about key to be created * @generateReset: [in] If TRUE generate EKreset otherwise use the passed value * @inputEKreset: [in] Authorization value to be used if generateReset is FALSE * @pubEndorsementKey: [out] The public endorsement key * @Checksum: [out] Hash of pubEndorsementKey and antiReplay * @outputEKreset: [out] The authorization value to use TPM_RevokeTrust * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 14.2) * This command creates the TPM endorsement key. It returns a failure code if * an endorsement key already exists. */ TPM_RESULT TPM_CreateRevocableEK( TPM_NONCE *antiReplay, TPM_KEY_PARMS *keyInfo, BOOL generateReset, TPM_NONCE *inputEKreset, TPM_PUBKEY *pubEndorsementKey, TPM_DIGEST *Checksum, TPM_NONCE *outputEKreset ); /** * TPM_RevokeTrust - clears the EK and sets the TPM to a pure default state * @EKReset: [in] The value that will be matched to EK Reset * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 14.3) * This command clears the EK and sets the TPM back to a pure default state. * The generation of the authorization value occurs during the generation of * the EK. It is the responsibility of the EK generator to properly protect * and disseminate the RevokeTrust authorization. */ TPM_RESULT TPM_RevokeTrust( TPM_NONCE *EKReset ); /** * tpm_get_pubek - extracts the public portion of the EK * @pubEndorsementKey: [out] The public endorsement key */ TPM_RESULT tpm_get_pubek( TPM_PUBKEY *pubEndorsementKey ); /** * TPM_ReadPubek - provides the public portion of the EK * @antiReplay: [in] Arbitrary data * @pubEndorsementKey: [out] The public endorsement key * @checksum: [out] Hash of pubEndorsementKey and antiReplay * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 14.4) * Provides the endorsement key public portion. This value should have * controls placed upon access as it is a privacy sensitive value. */ TPM_RESULT TPM_ReadPubek( TPM_NONCE *antiReplay, TPM_PUBKEY *pubEndorsementKey, TPM_DIGEST *checksum ); /** * TPM_DisablePubekRead - disables the TPM_ReadPubk command * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 14.5) * The TPM Owner may wish to prevent any entity from reading the PUBEK. * This command sets the non-volatile flag so that the TPM_ReadPubek * command always returns TPM_DISABLED_CMD. */ TPM_RESULT TPM_DisablePubekRead( TPM_AUTH *auth1 ); /** * TPM_OwnerReadInternalPub - provides the public portion of the EK or SRK * @keyHandle: [in] Handle for either PUBEK or SRK * @auth1: [in, out] Authorization protocol parameters * @publicPortion: [out] The public portion of the requested key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 14.6) * A TPM Owner authorized command that provides the public portion of * the EK or SRK. */ TPM_RESULT TPM_OwnerReadInternalPub( TPM_KEY_HANDLE keyHandle, TPM_AUTH *auth1, TPM_PUBKEY *publicPortion ); /* * Identity Creation and Activation ([TPM_Part3], Section 15) * [tpm_identity.c] */ /** * TPM_MakeIdentity - generates a new AIK * @identityAuth: [in] Encrypted usage authorization data for the new identity * @labelPrivCADigest: [in] Digest of the identity label and the new privacy CA * @idKeyParams: [in] All parameters of the new identity key * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @idKey: [out] The newly created identity key * @identityBindingSize: [out] The size of the output area for identityBinding * @identityBinding: [out] Signature of TPM_IDENTITY_CONTENTS using idKey * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 15.1) * Generate a new Attestation Identity Key (AIK). */ TPM_RESULT TPM_MakeIdentity( TPM_ENCAUTH *identityAuth, TPM_CHOSENID_HASH *labelPrivCADigest, TPM_KEY *idKeyParams, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_KEY *idKey, UINT32 *identityBindingSize, BYTE **identityBinding ); /** * TPM_ActivateIdentity - activates a TPM identity * @idKeyHandle: [in] Identity key to be activated * @blobSize: [in] Size of encrypted blob from CA * @blob: [in] The encrypted ASYM_CA_CONTENTS or TPM_EK_BLOB * @auth1: [in, out] Authorization protocol parameters (usageAuth) * @auth2: [in, out] Authorization protocol parameters (ownerAuth) * @symmetricKey: [out] The decrypted symmetric key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 15.2) * The purpose of TPM_ActivateIdentity is to twofold. The first purpose is to * obtain assurance that the credential in the TPM_SYM_CA_ATTESTATION is for * this TPM. The second purpose is to obtain the session key used to encrypt * the TPM_IDENTITY_CREDENTIAL. */ TPM_RESULT TPM_ActivateIdentity( TPM_KEY_HANDLE idKeyHandle, UINT32 blobSize, BYTE *blob, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_SYMMETRIC_KEY *symmetricKey ); /* * Integrity Collection and Reporting ([TPM_Part3], Section 16) * [tpm_integrity.c] * This section deals with what commands have direct access to the PCR. */ /** * TPM_Extend - adds a new measurement to a PCR * @pcrNum: [in] The PCR to be updated * @inDigest: [in] The 160 bit value representing the event to be recorded * @outDigest: [out] The PCR value after execution of the command * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 16.1) * This adds a new measurement to a Platform Configuration Register (PCR). */ TPM_RESULT TPM_Extend( TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, TPM_PCRVALUE *outDigest ); /** * TPM_PCRRead - provides the contents of a named PCR * @pcrIndex: [in] Index of the PCR to be read * @outDigest: [out] The current contents of the named PCR * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 16.2) * The TPM_PCRRead operation provides non-cryptographic reporting of the * contents of a named PCR. */ TPM_RESULT TPM_PCRRead( TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest ); /** * TPM_Quote - provides cryptographic reporting of PCR values * @keyHandle: [in] Handle of a loaded key that can sign the PCR values * @extrnalData: [in] 160 bits of externally supplied data (typically a nonce) * @targetPCR: [in] The indices of the PCRs that are to be reported * @auth1: [in, out] Authorization protocol parameters * @pcrData: [out] The indices and values of the PCRs listed in targetPCR * @sigSize: [out] The used size of the output area for the signature * @sig: [out] The signed data blob * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 16.3) * The TPM_Quote operation provides cryptographic reporting of PCR values. * A loaded key is required for operation TPM_Quote uses a key to sign a * statement that names the current value of a chosen PCR and externally * supplied data (which may be a nonce supplied by a Challenger). */ TPM_RESULT TPM_Quote( TPM_KEY_HANDLE keyHandle, TPM_NONCE *extrnalData, TPM_PCR_SELECTION *targetPCR, TPM_AUTH *auth1, TPM_PCR_COMPOSITE *pcrData, UINT32 *sigSize, BYTE **sig ); /** * TPM_PCR_Reset - resets the indicated PCRs * @pcrSelection: [in] The PCRs to reset * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 16.4) * Resets the indicated PCRs. This command uses the locality modifier. * The modifier for a command to indicate locality is a platform specific * issue. */ TPM_RESULT TPM_PCR_Reset( TPM_PCR_SELECTION *pcrSelection ); /** * TPM_Quote2 - provides cryptographic reporting of PCR values * @keyHandle: [in] Handle of a loaded key that can sign the PCR values * @extrnalData: [in] 160 bits of externally supplied data (typically a nonce) * @targetPCR: [in] The indices of the PCRs that are to be reported * @addVersion: [in] When TRUE add TPM_CAP_VERSION_INFO to the output * @auth1: [in, out] Authorization protocol parameters * @pcrData: [out] The value created and signed for the quote * @versionInfoSize: [out] Size of the version info * @versionInfo: [out] The version info * @sigSize: [out] The used size of the output area for the signature * @sig: [out] The signed data blob * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 16.5) */ TPM_RESULT TPM_Quote2( TPM_KEY_HANDLE keyHandle, TPM_NONCE *externalData, TPM_PCR_SELECTION *targetPCR, BOOL addVersion, TPM_AUTH *auth1, TPM_PCR_INFO_SHORT *pcrData, UINT32 *versionInfoSize, TPM_CAP_VERSION_INFO *versionInfo, UINT32 *sigSize, BYTE **sig ); /** * tpm_compute_pcr_digest - computes a PCR composite hash * @pcrSelection: [in] The PCRs to include * @digest: [out] The computed composite hash * @composite: [out] If not NULL the used composite is stored into it * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.3.1) * Computes the PCR composite hash over a given set of PCRs. */ TPM_RESULT tpm_compute_pcr_digest( TPM_PCR_SELECTION *pcrSelection, TPM_COMPOSITE_HASH *digest, TPM_PCR_COMPOSITE *composite ); /** * tpm_verify_pcr - verifies the PCR composite hash of the specified key * @key: [in] The key whose PCR composite hash should be verified * @atrelease: [in] If TRUE the AtRelease composite hash is verified * @atcreation: [in] If TRUE the AtCreation composite hash is verified * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 5.3.1) * Computes the PCR composite hash over a given set of PCRs. */ TPM_RESULT tpm_verify_pcr( TPM_KEY_DATA *key, BOOL atrelease, BOOL atcreation ); /* * Authorization Changing ([TPM_Part3], Section 17) * [tpm_authorization.c] */ /** * TPM_ChangeAuth - changes the authorization data for the entity * @parentHandle: [in] Handle of the parent key to the entity * @protocolID: [in] The protocol in use * @newAuth: [in] The encrypted new authorization data for the entity * @entityType: [in] The type of entity to be modified * @encDataSize: [in] The size of the encData parameter * @encData: [in] The encrypted entity that is to be modified * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The modified, encrypted entity * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 17.1) * The TPM_ChangeAuth command allows the owner of an entity to change the * authorization data for the entity. TPM_ChangeAuth requires the encryption * of one parameter (NewAuth). */ 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_ChangeAuthOwner - changes the authorization data for the TPM Owner * @protocolID: [in] The protocol in use * @newAuth: [in] The encrypted new authorization data for the entity * @entityType: [in] The type of entity to be modified * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 17.2) * The TPM_ChangeAuthOwner command allows the owner of an entity to change * the authorization data for the TPM Owner or the SRK. This command requires * authorization from the current TPM Owner to execute. */ TPM_RESULT TPM_ChangeAuthOwner( TPM_PROTOCOL_ID protocolID, TPM_ENCAUTH *newAuth, TPM_ENTITY_TYPE entityType, TPM_AUTH *auth1 ); /* * Authorization Sessions ([TPM_Part3], Section 18) * [tpm_authorization.c] */ /** * TPM_OIAP - creates an authorization handle for the OIAP * @authHandle: [out] Handle that points to the authorization state * @nonceEven: [out] Nonce associated with session * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 18.1) * The TPM_OIAP command creates an authorization handle and generates * nonceEven for the Object-Independent Authorization Protocol (OIAP). */ TPM_RESULT TPM_OIAP( TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven ); /** * TPM_OSAP - creates an authorization handle for the OSAP * @entityType: [in] The type of entity in use * @entityValue: [in] The selection value based on entityType * @nonceOddOSAP: [in] The nonce generated by the caller * @authHandle: [out] Handle that points to the authorization state * @nonceEven: [out] Nonce associated with session * @nonceEvenOSAP: [out] Nonce associated with shared secret * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 18.2) * The TPM_OSAP command creates an authorization handle, the shared secret * and generates nonceEven and nonceEvenOSAP for the Object-Specific * Authorization Protocol (OSAP). */ TPM_RESULT TPM_OSAP( TPM_ENTITY_TYPE entityType, UINT32 entityValue, TPM_NONCE *nonceOddOSAP, TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven, TPM_NONCE *nonceEvenOSAP ); /** * TPM_DSAP - creates an authorization handle for the DSAP * @entityType [in] The type of delegation information to use * @keyHandle: [in] Key for which delegated authority corresponds * @nonceOddDSAP: [in] The nonce generated by the caller * @entityValueSize: [in] The size of entityValue * @entityValue: [in] The entity value based on entityType * @authHandle: [out] Handle that points to the authorization state * @nonceEven: [out] Nonce associated with session * @nonceEvenDSAP: [out] Nonce associated with shared secret * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 18.3) * The TPM_DSAP command creates the authorization handle using a delegated * authorization value passed into the command as an encrypted blob or from * the internal delegation table for the Delegate-Specific Authorization * Protocol (DSAP). */ TPM_RESULT TPM_DSAP( TPM_ENTITY_TYPE entityType, TPM_KEY_HANDLE keyHandle, TPM_NONCE *nonceOddDSAP, UINT32 entityValueSize, BYTE *entityValue, TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven, TPM_NONCE *nonceEvenDSAP ); /** * TPM_SetOwnerPointer - sets an owner secret for OIAP or OSAP * @entityType: [in] The type of entity in use * @entityValue: [in] The selection value based on entityType, * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 18.4) * This command will set a reference to which secret the TPM will use when * executing an owner secret related OIAP or OSAP session. This command * should only be used if legacy code must be enabled for delegation to work. */ TPM_RESULT TPM_SetOwnerPointer( TPM_ENTITY_TYPE entityType, UINT32 entityValue ); /** * tpm_verify_auth - verifies an authorization session * @auth: [in] The handle to the authorization session * @secret: [in] The secret associated with the resource * @handle: [in] The handle used to access the resource * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 18.1.1 and 18.2.1) * Verifies a OIAP and OSAP session. In addition to the protocol * parameters auth->digest is supposed to contain the the SHA-1 digest * of the input parameters. */ TPM_RESULT tpm_verify_auth( TPM_AUTH *auth, TPM_SECRET secret, TPM_HANDLE handle ); /** * tpm_decrypt_auth_secret - decrypts an authorization secret * @encAuth: [in] The encrypted authorization secret * @secret: [in] The shared secret of the OSAP session * @nonce: [in] The nonce for decryption * @plainAuth: [out]: The decrypted authorization secret * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: * Decrypts an encrypted authorization secret by xoring it with * the key SHA-1(secret||nonce). */ void tpm_decrypt_auth_secret( TPM_ENCAUTH encAuth, TPM_SECRET secret, TPM_NONCE *nonce, TPM_SECRET plainAuth ); /* * Delegation Commands ([TPM_Part3], Section 19) * [tpm_delegation.c] */ /** * TPM_Delegate_Manage - manages the Family tables * @familyID: [in] The familyID that is to be managed * @opFlag: [in] Operation to be performed by this command * @opDataSize: [in] Size in bytes of opData * @opData: [in] Data necessary to implement opFlag * @auth1: [in, out] Authorization protocol parameters * @retDataSize: [out] Size in bytes of retData * @retData: [out] Returned data * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.1) * TPM_Delegate_Manage is the fundamental process for managing the Family * tables, including enabling/disabling Delegation for a selected Family. */ TPM_RESULT TPM_Delegate_Manage( TPM_FAMILY_ID familyID, TPM_FAMILY_OPERATION opFlag, UINT32 opDataSize, BYTE *opData, TPM_AUTH *auth1, UINT32 *retDataSize, BYTE **retData ); /** * TPM_Delegate_CreateKeyDelegation - delegates privilege to use a key * @keyHandle: [in] Handle of a loaded key * @publicInfo: [in] The public information necessary to fill in the blob * @delAuth: [in] The encrypted new authorization data for the blob * @auth1: [in, out] Authorization protocol parameters * @blob: [out] The partially encrypted delegation information * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.2) * This command delegates privilege to use a key by creating a blob that can * be used by TPM_DSAP. */ TPM_RESULT TPM_Delegate_CreateKeyDelegation( TPM_KEY_HANDLE keyHandle, TPM_DELEGATE_PUBLIC *publicInfo, TPM_ENCAUTH *delAuth, TPM_AUTH *auth1, TPM_DELEGATE_KEY_BLOB *blob ); /** * TPM_Delegate_CreateOwnerDelegation - delegates the Owner's privilege * @increment: [in] Flag dictates whether verificationCount will be incremented * @publicInfo: [in] The public parameters for the blob * @delAuth: [in] The encrypted new authorization data for the blob * @auth1: [in, out] Authorization protocol parameters * @blob: [out] The partially encrypted delegation information * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.3) * TPM_Delegate_CreateOwnerDelegation delegates the Owner's privilege to use * a set of command ordinals, by creating a blob. Such blobs can be used as * input data for TPM_DSAP or TPM_Delegate_LoadOwnerDelegation. */ TPM_RESULT TPM_Delegate_CreateOwnerDelegation( BOOL increment, TPM_DELEGATE_PUBLIC *publicInfo, TPM_ENCAUTH *delAuth, TPM_AUTH *auth1, TPM_DELEGATE_OWNER_BLOB *blob ); /** * TPM_Delegate_LoadOwnerDelegation - loads a delegate table row blob * @index: [in] The index of the delegate row to be written * @blob: [in] the delegation information * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.4) * This command loads a delegate table row blob into a non-volatile delegate * table row. Delegate_LoadOwnerDelegation can be used during manufacturing or * on first boot (when no Owner is installed), or after an Owner is installed. */ TPM_RESULT TPM_Delegate_LoadOwnerDelegation( TPM_DELEGATE_INDEX index, TPM_DELEGATE_OWNER_BLOB *blob, TPM_AUTH *auth1 ); /** * TPM_Delegate_ReadTable - reads from the family and delegate tables * @familyTableSize: [out] Size in bytes of familyTable * @familyTable: [out] Array of TPM_FAMILY_TABLE_ENTRY elements * @delegateTableSize: [out] Size in bytes of delegateTable * @delegateTable: [out] Array of TPM_DELEGATE_TABLE_PUBLIC elements * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.5) * This command is used to read from the TPM the public contents of the * family and delegate tables that are stored on the TPM. */ TPM_RESULT TPM_Delegate_ReadTable( UINT32 *familyTableSize, BYTE **familyTable , UINT32 *delegateTableSize, BYTE **delegateTable ); /** * TPM_Delegate_UpdateVerification - updates the verificationCount * @inputSize: [in] The size of inputData * @inputData: [in] TPM_DELEGATE_KEY_BLOB, -OWNER_BLOB or table index * @auth1: [in, out] Authorization protocol parameters * @outputSize: [out] The size of the output * @outputData: [out] TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.6) * UpdateVerification sets the verificationCount in an entity (a blob or a * delegation row) to the current family value, in order that the delegations * represented by that entity will continue to be accepted by the TPM. */ TPM_RESULT TPM_Delegate_UpdateVerification( UINT32 inputSize, BYTE *inputData, TPM_AUTH *auth1, UINT32 *outputSize, BYTE **outputData ); /** * TPM_Delegate_VerifyDelegation - verifies a delegate blob * @delegateSize: [in] The length of the delegated information blob * @delegation: [in] TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 19.7) * VerifyDelegation loads a delegate blob and returns success or failure, * depending on whether the blob is currently valid. */ TPM_RESULT TPM_Delegate_VerifyDelegation( UINT32 delegateSize, BYTE *delegation ); /** * tpm_get_family_row - returns the family row for the specified id * @id: [in] family id * Returns: The matching family row on success, NULL otherwise. */ TPM_FAMILY_TABLE_ENTRY *tpm_get_family_row( TPM_FAMILY_ID id ); /** * tpm_get_delegate_row - returns the delegate row for the specified index * @row: [in] row index * Returns: The matching delegate row on success, NULL otherwise. */ TPM_DELEGATE_TABLE_ROW *tpm_get_delegate_row( UINT32 row ); /** * tpm_compute_owner_blob_digest - computes the digest of an owner blob * @blob: [in] Owner blob * @digest: [out] Digest of the specified owner blob */ void tpm_compute_owner_blob_digest( TPM_DELEGATE_OWNER_BLOB *blob, TPM_DIGEST *digest ); /** * tpm_compute_key_blob_digest - computes the digest of a key blob * @blob: [in] Key blob * @digest: [out] Digest of the specified key blob */ void tpm_compute_key_blob_digest( TPM_DELEGATE_KEY_BLOB *blob, TPM_DIGEST *digest ); /** * tpm_encrypt_sensitive - encrypts a TPM_DELEGATE_SENSITIVE structure * @iv: [in] IV value * @iv_size: [in] Size of the IV value * @sensitive: [in] structure to encrypt * @enc: [out] Encrypted structure * @enc_size: [out] Size of the encrypted structure * Returns 0 on success, -1 otherwise. */ int tpm_encrypt_sensitive( BYTE *iv, UINT32 iv_size, TPM_DELEGATE_SENSITIVE *sensitive, BYTE **enc, UINT32 *enc_size ); /** * tpm_decrypt_sensitive - decrypts a TPM_DELEGATE_SENSITIVE structure * @iv: [in] IV value * @iv_size: [in] Size of the IV value * @enc: [in] Encrypted structure * @enc_size: [in] Size of the encrypted structure * @sensitive: [out] decrypted structure * Returns 0 on success, -1 otherwise. */ int tpm_decrypt_sensitive( BYTE *iv, UINT32 iv_size, BYTE *enc, UINT32 enc_size, TPM_DELEGATE_SENSITIVE *sensitive, BYTE **buf ); /* * Non-volatile Storage ([TPM_Part3], Section 20) * [tpm_nv_storage.c] * This section handles the allocation and use of the TPM non-volatile storage. */ /** * TPM_NV_DefineSpace - establishes the necessary space * @pubInfo: [in] The public parameters of the NV area * @encAuth: [in] The encrypted authorization (if reqired) * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 20.1) * This establishes the space necessary for the indicated index. The definition * will include the access requirements for writing and reading the area. The * space definition size does not include the area needed to manage the space. */ TPM_RESULT TPM_NV_DefineSpace( TPM_NV_DATA_PUBLIC *pubInfo, TPM_ENCAUTH *encAuth, TPM_AUTH *auth1 ); /** * TPM_NV_WriteValue - writes a value to a defined NV area * @nvIndex: [in] The index of the area to set * @offset: [in] The offset into the NV Area * @dataSize: [in] The size of the data area * @data: [in] The data to set the area to * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 20.2) * This command writes a value to a defined area. The write can be TPM Owner * authorized or unauthorized and protected by other attributes and will work * when no TPM Owner is present. */ TPM_RESULT TPM_NV_WriteValue( TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 dataSize, BYTE *data, TPM_AUTH *auth1 ); /** * TPM_NV_WriteValueAuth - writes a value to a protected NV area * @nvIndex: [in] The index of the area to set * @offset: [in] The offset into the chunk * @dataSize: [in] The size of the data area * @data: [in] The data to set the area to * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 20.3) * This command writes to a previously defined area. The area must require * authorization to write. This command is for using when authorization other * than the owner authorization is to be used. */ TPM_RESULT TPM_NV_WriteValueAuth( TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 dataSize, BYTE *data, TPM_AUTH *auth1 ); /** * TPM_NV_ReadValue - reads a value from a defined NV area * @nvIndex: [in] The index of the area to set * @offset: [in] The offset into the area * @inDataSize: [in] The size of the data area * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The size of the data area * @data: [out] The data to set the area to * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 20.4) * Read a value from the NV store. This command uses optional owner * authorization. */ TPM_RESULT TPM_NV_ReadValue( TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 inDataSize, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **data ); /** * TPM_NV_ReadValueAuth - reads a value from a protected NV area * @nvIndex: [in] The index of the area to set * @offset: [in] The offset from the data area * @inDataSize: [in] The size of the data area * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The size of the data area * @data: [out] The data * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 20.5) * This command requires that the read be authorized by a value set * with the blob. */ TPM_RESULT TPM_NV_ReadValueAuth( TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 inDataSize, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **data ); /** * tpm_nv_remove_data - removes the specified data from the NV area * @nv: [in] Data area to be removed */ void tpm_nv_remove_data( TPM_NV_DATA_SENSITIVE *nv ); /* * Session Management ([TPM_Part3], Section 21) * [tpm_context.c] */ /** * TPM_KeyControlOwner - controls attributes of keys within the key cache * @keyHandle: [in] Handle of a loaded key * @pubKey: [in] The public key associated with the loaded key * @bitName: [in] The name of the bit to be modified * @bitValue: [in] The value to set the bit to * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 21.1) * This command controls some attributes of keys that are stored within * the TPM key cache. */ TPM_RESULT TPM_KeyControlOwner( TPM_KEY_HANDLE keyHandle, TPM_PUBKEY pubKey, UINT32 bitName, BOOL bitValue, TPM_AUTH *auth1 ); /** * TPM_SaveContext - saves a loaded resource outside the TPM * @handle: [in] Handle of the resource being saved * @resourceType: [in] The type of resource that is being saved * @label[16]: [in] Label for identification purposes * @contextSize: [out] The actual size of the outgoing context blob * @contextBlob: [out] The context blob * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 21.2) * SaveContext saves a loaded resource outside the TPM. After successful * execution of the command the TPM automatically releases the internal * memory for sessions but leaves keys in place. */ TPM_RESULT TPM_SaveContext( TPM_HANDLE handle, TPM_RESOURCE_TYPE resourceType, const BYTE label[16], UINT32 *contextSize, TPM_CONTEXT_BLOB *contextBlob ); /** * TPM_LoadContext - loads a previously saved context into the TPM * @entityHandle: [in] The hint handle the TPM MAY use to locate a OSAP session * @keepHandle: [in] Indication if the handle MUST be preserved * @contextSize: [in] The size of the following context blob * @contextBlob: [in] The context blob * @handle: [out] Handle assigned to the resource * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 21.3) * LoadContext loads into the TPM a previously saved context. The command * returns the type of blob and a handle. */ TPM_RESULT TPM_LoadContext( TPM_HANDLE entityHandle, BOOL keepHandle, UINT32 contextSize, TPM_CONTEXT_BLOB *contextBlob, TPM_HANDLE *handle ); /** * tpm_get_free_session - allocates a new session * @type: [in] The session type * Returns: the session handle on success, TPM_INVALID_HANDLE otherwise. */ UINT32 tpm_get_free_session( BYTE type ); /** * tpm_invalidate_sessions - invalidates all sessions associated with the handle * @handle: [in] Session handle */ void tpm_invalidate_sessions( TPM_HANDLE handle ); /* * Eviction ([TPM_Part3], Section 22) * [tpm_eviction.c] * The TPM has numerous resources held inside of the TPM that may need * eviction. The need for eviction occurs when the number or resources * in use by the TPM exceed the available space. In version 1.1 there were * separate commands to evict separate resource types. This new command * set uses the resource types defined for context saving and creates a * generic command that will evict all resource types. */ /** * TPM_FlushSpecific - flushes a specific handle * @handle: [in] Handle of the item to flush * @resourceType: [in] The type of resource that is being flushed * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 22.1) * TPM_FlushSpecific flushes from the TPM a specific handle. */ TPM_RESULT TPM_FlushSpecific( TPM_HANDLE handle, TPM_RESOURCE_TYPE resourceType ); /* * Timing Ticks ([TPM_Part3], Section 23) * [tpm_ticks.c] * The TPM timing ticks are always available for use. The association of * timing ticks to actual time is a protocol that occurs outside of the TPM. * See the design document for details. */ /** * TPM_GetTicks - provides the current tick count * @currentTime: [out] The current time held in the TPM descriptions * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 23.2) * This command provides the current tick count of the TPM. */ TPM_RESULT TPM_GetTicks( TPM_CURRENT_TICKS *currentTime ); /** * TPM_TickStampBlob - applies a time stamp to the passed blob * @keyHandle: [in] Handle of a loaded key that can perform digital signatures * @antiReplay: [in] Anti replay value to added to signature * @digestToStamp: [in] The digest to perform the tick stamp on * @auth1: [in, out] Authorization protocol parameters * @currentTicks: [out] The current time according to the TPM * @sigSize: [out] The length of the returned digital signature * @sig: [out] The resulting digital signature * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 23.3) * This command applies a time stamp to the passed blob. The TPM makes no * representation regarding the blob merely that the blob was present at * the TPM at the time indicated. */ TPM_RESULT TPM_TickStampBlob( TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_DIGEST *digestToStamp, TPM_AUTH *auth1, TPM_CURRENT_TICKS *currentTicks, UINT32 *sigSize, BYTE **sig ); /** * tpm_update_ticks - updates the current tick session */ void tpm_update_ticks(void); /* * Transport Sessions ([TPM_Part3], Section 24) * [tpm_transport.c] */ /** * TPM_EstablishTransport - establishes a transport session * @encHandle: [in] Handle to the key that encrypted the blob * @transPublic: [in] The public information describing the transport session * @secretSize: [in] The size of the secret Area * @secret: [in] The encrypted secret area * @auth1: [in, out] Authorization protocol parameters * @transHandle: [out] Handle for the transport session * @locality [out] The locality that called this command * @currentTicks: [out] The current tick count * @transNonce: [out] The even nonce in use for subsequent execute transport * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 24.1) * This establishes a transport session. Depending on the attributes * specified for the session this may establish shared secrets, encryption * keys and session logs. The session will be in use for by the * TPM_ExecuteTransport command. */ TPM_RESULT TPM_EstablishTransport( TPM_KEY_HANDLE encHandle, TPM_TRANSPORT_PUBLIC *transPublic, UINT32 secretSize, BYTE *secret, TPM_AUTH *auth1, TPM_TRANSHANDLE *transHandle, TPM_MODIFIER_INDICATOR *locality, TPM_CURRENT_TICKS *currentTicks, TPM_NONCE *transNonce ); /** * TPM_ExecuteTransport - executes a wrapped TPM command * @inWrappedCmdSize: [in] Size of the wrapped command * @inWrappedCmd: [in] The wrapped command * @auth1: [in, out] Authorization protocol parameters * @currentTicks: [out] The current ticks when the command was executed * @locality [out] The locality that called this command * @outWrappedCmdSize: [out] Size of the wrapped command * @outWrappedCmd: [out] The wrapped command * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 24.2) * Delivers a wrapped TPM command to the TPM where the TPM unwraps the * command and then executes the command. */ TPM_RESULT TPM_ExecuteTransport( UINT32 inWrappedCmdSize, BYTE *inWrappedCmd, TPM_AUTH *auth1, UINT64 *currentTicks, TPM_MODIFIER_INDICATOR *locality, UINT32 *outWrappedCmdSize, BYTE **outWrappedCmd ); /** * TPM_ReleaseTransportSigned - completes a transport session * @Key: [in] The key that will perform the signing * @antiReplay: [in] Value provided by caller for anti-replay protection * @auth1: [in, out] Authorization protocol parameters * @auth2: [in, out] Authorization protocol parameters * @locality [out] The locality that called this command * @currentTicks: [out] The current ticks when the command was executed * @signSize: [out] The size of the signature area * @signature: [out] The signature of the digest * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 24.3) * This command completes a transport session. If logging for this session * is turned on, then this command returns a signed hash of all operations * performed during the session. This command serves no purpose if logging * is turned off and results in an error if attempted. */ TPM_RESULT TPM_ReleaseTransportSigned( TPM_KEY_HANDLE Key, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_MODIFIER_INDICATOR *locality, TPM_CURRENT_TICKS *currentTicks, UINT32 *signSize, BYTE **signature ); /* * Monotonic Counter ([TPM_Part3], Section 25) * [tpm_counter.c] */ /** * TPM_CreateCounter - creates a counter but does not select it * @authData: [in] The encrypted auth data for the new counter * @label[4]: [in] Label to associate with counter * @auth1: [in, out] Authorization protocol parameters * @countID: [out] Handle for the counter * @counterValue: [out] The starting counter value * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 25.1) * This command creates a counter but does not select it. Counter creation * assigns an authorization value to the counter and sets the counters * original start value to the current internal base value plus one. */ TPM_RESULT TPM_CreateCounter( TPM_ENCAUTH *authData, BYTE label[4], TPM_AUTH *auth1, TPM_COUNT_ID *countID, TPM_COUNTER_VALUE *counterValue ); /** * TPM_IncrementCounter - increments the indicated counter by one * @countID: [in] Handle of a valid counter * @auth1: [in, out] Authorization protocol parameters * @count: [out] The counter value * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 25.2) * This authorized command increments the indicated counter by one. Once a * counter has been incremented then all subsequent increments must be for * the same handle until a successful TPM_Startup(ST_CLEAR) is executed. */ TPM_RESULT TPM_IncrementCounter( TPM_COUNT_ID countID, TPM_AUTH *auth1, TPM_COUNTER_VALUE *count ); /** * TPM_ReadCounter - provides the current counter number * @countID: [in] ID value of the counter * @count: [out] The counter value * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 25.3) * Reading the counter provides the caller with the current number * in the sequence. */ TPM_RESULT TPM_ReadCounter( TPM_COUNT_ID countID, TPM_COUNTER_VALUE *count ); /** * TPM_ReleaseCounter - releases a counter * @countID: [in] ID value of the counter * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 25.4) * This command releases a counter such that no reads or increments * of the indicated counter will succeed. */ TPM_RESULT TPM_ReleaseCounter( TPM_COUNT_ID countID, TPM_AUTH *auth1 ); /** * TPM_ReleaseCounterOwner - releases a counter * @countID: [in] ID value of the counter * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 25.5) * This command releases a counter such that no reads or increments * of the indicated counter will succeed. */ TPM_RESULT TPM_ReleaseCounterOwner( TPM_COUNT_ID countID, TPM_AUTH *auth1 ); /* * DAA commands ([TPM_Part3], Section 26) * [tpm_daa.c] * Operations that are necessary to setup a TPM for DAA, execute the * JOIN process, and execute the SIGN process. */ /** * TPM_DAA_Join - establishes the DAA parameters * @handle: [in] Session handle * @stage: [in] Processing stage of join * @inputSize0: [in] Size of inputData0 for this stage of JOIN * @inputData0: [in] Data to be used by this capability * @inputSize1: [in] Size of inputData1 for this stage of JOIN * @inputData1: [in] Data to be used by this capability * @auth1: [in, out] Authorization protocol parameters * @ordinal: [out] Command ordinal: TPM_ORD_DAA_Join * @outputSize: [out] Size of outputData * @outputData: [out] Data produced by this capability * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 26.1) * TPM_DAA_Join is the process that establishes the DAA parameters in * the TPM for a specific DAA issuing authority. */ TPM_RESULT TPM_DAA_Join( TPM_HANDLE handle, BYTE stage, UINT32 inputSize0, BYTE *inputData0, UINT32 inputSize1, BYTE *inputData1, TPM_AUTH *auth1, TPM_COMMAND_CODE *ordinal, UINT32 *outputSize, BYTE **outputData ); /** * TPM_DAA_Sign - proves the attestation held by a TPM * @handle: [in] Handle to the sign session * @stage: [in] Stage of the sign process * @inputSize0: [in] Size of inputData0 for this stage of DAA_Sign * @inputData0: [in] Data to be used by this capability * @inputSize1: [in] Size of inputData1 for this stage of DAA_Sign * @inputData1: [in] Data to be used by this capability * @auth1: [in, out] Authorization protocol parameters * @ordinal: [out] Command ordinal:TPM_ORD_DAA_SIGN * @outputSize: [out] Size of outputData * @outputData: [out] Data produced by this capability * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 26.2) * TPM_DAA_Sign responds to a challenge and proves the attestation * held by a TPM without revealing the attestation held by that TPM. */ TPM_RESULT TPM_DAA_Sign( TPM_HANDLE handle, BYTE stage, UINT32 inputSize0, BYTE *inputData0, UINT32 inputSize1, BYTE *inputData1, TPM_AUTH *auth1, TPM_COMMAND_CODE *ordinal, UINT32 *outputSize, BYTE **outputData ); /** * tpm_get_free_daa_session - allocates a new DAA session * Returns: the session handle on success, TPM_INVALID_HANDLE otherwise. */ UINT32 tpm_get_free_daa_session(void); /* * Deprecated commands ([TPM_Part3], Section 28) * [tpm_deprecated.c] * This section covers the commands that were in version 1.1 but now have * new functionality in other functions. The deprecated commands are still * available in 1.2 but all new software should use the new functionality. * There is no requirement that the deprecated commands work with new * structures. */ /** * TPM_EvictKey - evicts a key * @evictHandle: [in] Handle of the key to be evicted * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.1.1) * The key commands are deprecated as the new way to handle keys is to use * the standard context commands. So TPM_EvictKey is now handled by * TPM_FlushSpecific, TPM_TerminateHandle by TPM_FlushSpecific. */ TPM_RESULT TPM_EvictKey( TPM_KEY_HANDLE evictHandle ); /** * TPM_Terminate_Handle - clears out information in a session handle * @handle: [in] Handle to terminate * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.1.2) * This allows the TPM manager to clear out information in a session handle. */ TPM_RESULT TPM_Terminate_Handle( TPM_AUTHHANDLE handle ); /** * TPM_SaveKeyContext - saves a loaded key outside the TPM * @keyHandle: [in] The key which will be kept outside the TPM * @keyContextSize: [out] The actual size of the outgoing key context blob * @keyContextBlob: [out] The key context blob * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.2.1) * SaveKeyContext saves a loaded key outside the TPM. After creation of the * key context blob the TPM automatically releases the internal memory used * by that key. The format of the key context blob is specific to a TPM. */ TPM_RESULT TPM_SaveKeyContext( TPM_KEY_HANDLE keyHandle, UINT32 *keyContextSize, BYTE **keyContextBlob ); /** * TPM_LoadKeyContext - loads a key context blob into the TPM * @keyContextSize: [in] The size of the following key context blob * @keyContextBlob: [in] The key context blob * @keyHandle: [out] Handle assigned to the key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.2.2) * LoadKeyContext loads a key context blob into the TPM previously retrieved * by a SaveKeyContext call. After successful completion the handle returned * by this command can be used to access the key. */ TPM_RESULT TPM_LoadKeyContext( UINT32 keyContextSize, BYTE *keyContextBlob, TPM_KEY_HANDLE *keyHandle ); /** * TPM_SaveAuthContext - saves an authorization session outside the TPM * @authHandle: [in] Authorization session which will be kept outside the TPM * @authContextSize: [out] The size of the outgoing authorization context blob * @authContextBlob: [out] The authorization context blob * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.2.3) * SaveAuthContext saves a loaded authorization session outside the TPM. * The format of the authorization context blob is specific to a TPM. */ TPM_RESULT TPM_SaveAuthContext( TPM_AUTHHANDLE authHandle, UINT32 *authContextSize, BYTE **authContextBlob ); /** * TPM_LoadAuthContext - loads an authorization context blob into the TPM * @authContextSize: [in] The size of the following authorization context blob * @authContextBlob: [in] The authorization context blob * @authHandle: [out] Handle assigned to the authorization session * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.2.4) * LoadAuthContext loads an authorization context blob into the TPM previously * retrieved by a SaveAuthContext call. After successful completion the handle * returned by this command can be used to access the authorization session. */ TPM_RESULT TPM_LoadAuthContext( UINT32 authContextSize, BYTE *authContextBlob, TPM_KEY_HANDLE *authHandle ); /** * TPM_DirWriteAuth - provides write access to the DIRs * @dirIndex: [in] Index of the DIR * @newContents: [in] New value to be stored in named DIR * @auth1: [in, out] Authorization protocol parameters * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.3.1) * The TPM_DirWriteAuth operation provides write access to the Data Integrity * Registers. DIRs are non-volatile memory registers held in a TPM-shielded * location. */ TPM_RESULT TPM_DirWriteAuth( TPM_DIRINDEX dirIndex, TPM_DIRVALUE *newContents, TPM_AUTH *auth1 ); /** * TPM_DirRead - provides read access to the DIRs * @dirIndex: [in] Index of the DIR to be read * @dirContents: [out] The current contents of the named DIR * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.3.2) * The TPM_DirRead operation provides read access to the DIRs. No * authentication is required to perform this action. */ TPM_RESULT TPM_DirRead( TPM_DIRINDEX dirIndex, TPM_DIRVALUE *dirContents ); /** * TPM_ChangeAuthAsymStart - starts the ChangeAuth process * @idHandle: [in] Handle of a loaded identity ID key * @antiReplay: [in] The nonce to be inserted into the certifyInfo structure * @inTempKey: [in] Structure containing all parameters of the ephemeral key * @auth1: [in, out] Authorization protocol parameters * @certifyInfo: [out] The certifyInfo structure that is to be signed * @sigSize: [out] The used size of the output area for the signature * @sig: [out] The signature of the certifyInfo parameter * @ephHandle: [out] Handle to be used by ChangeAuthAsymFinish for ephemeral key * @outTempKey: [out] Structure containing all parameters and public part of ephemeral key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.4.1) * The TPM_ChangeAuthAsymStart starts the process of changing authorization * for an entity. It sets up an OIAP session that must be retained for use by * its twin TPM_ChangeAuthAsymFinish command. */ TPM_RESULT TPM_ChangeAuthAsymStart( TPM_KEY_HANDLE idHandle, TPM_NONCE *antiReplay, TPM_KEY_PARMS *inTempKey, TPM_AUTH *auth1, TPM_CERTIFY_INFO *certifyInfo, UINT32 *sigSize, BYTE **sig , TPM_KEY_HANDLE *ephHandle, TPM_KEY *outTempKey ); /** * TPM_ChangeAuthAsymFinish - terminates the ChangeAuth process * @parentHandle: [in] Handle of the parent key for the input data * @ephHandle: [in] Handle for the ephemeral key * @entityType: [in] The type of entity to be modified * @newAuthLink: [in] HMAC over the old and new authorization values * @newAuthSize: [in] Size of encNewAuth * @encNewAuth: [in] New authorization data encrypted with ephemeral key * @encDataSize: [in] The size of the inData parameter * @encData: [in] The encrypted entity that is to be modified * @auth1: [in, out] Authorization protocol parameters * @outDataSize: [out] The used size of the output area for outData * @outData: [out] The modified, encrypted entity * @saltNonce: [out] A nonce value to add entropy to the changeProof value * @changeProof: [out] Proof that authorization data has changed * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.4.2) * The TPM_ChangeAuth command allows the owner of an entity to change the * authorization data for the entity. The command requires knowledge of * the existing authorization information. */ TPM_RESULT TPM_ChangeAuthAsymFinish( TPM_KEY_HANDLE parentHandle, TPM_KEY_HANDLE ephHandle, TPM_ENTITY_TYPE entityType, TPM_HMAC *newAuthLink, UINT32 newAuthSize, BYTE *encNewAuth, UINT32 encDataSize, BYTE *encData, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData , TPM_NONCE *saltNonce, TPM_DIGEST *changeProof ); /** * TPM_Reset - releases all resources * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.5) * TPM_Reset releases all resources associated with existing authorization * sessions. This is useful if a TSS driver has lost track of the state in * the TPM. */ TPM_RESULT TPM_Reset(void); /** * TPM_CertifySelfTest - performs a full self-test and signs the result * @keyHandle: [in] Handle of a loaded key that can perform digital signatures * @antiReplay: [in] AnitReplay nonce to prevent replay of messages * @auth1: [in, out] Authorization protocol parameters * @sigSize: [out] The length of the returned digital signature * @sig: [out] The resulting digital signature * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.6) * CertifySelfTest causes the TPM to perform a full self-test and return * an authenticated value if the test passes. */ TPM_RESULT TPM_CertifySelfTest( TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_AUTH *auth1, UINT32 *sigSize, BYTE **sig ); /** * TPM_OwnerReadPubek - provides the endorsement key public portion * @auth1: [in, out] Authorization protocol parameters * @pubEndorsementKey: [out] The public endorsement key * Returns: TPM_SUCCESS on success, a TPM error code otherwise. * * Description: ([TPM_Part3], Section 28.7) * Provides the endorsement key public portion. */ TPM_RESULT TPM_OwnerReadPubek( TPM_AUTH *auth1, TPM_PUBKEY *pubEndorsementKey ); /* * Error handling * [tpm_error.c] */ /** * tpm_error_to_string - converts the specified error code into a string message * @res: [in] Error code * Returns: Human-readable description of the error code. */ const char *tpm_error_to_string( TPM_RESULT res ); #endif /* _TPM_COMMANDS_H_ */ ================================================ FILE: tpm/tpm_context.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_context.c 452 2010-07-19 19:05:05Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "tpm_marshalling.h" #include #include /* * Session Management ([TPM_Part3], Section 21) */ UINT32 tpm_get_free_session(BYTE type) { UINT32 i; for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpmData.stany.data.sessions[i].type == TPM_ST_INVALID) { tpmData.stany.data.sessions[i].type = type; if (type == TPM_ST_TRANSPORT) return INDEX_TO_TRANS_HANDLE(i); else return INDEX_TO_AUTH_HANDLE(i); } } return TPM_INVALID_HANDLE; } void tpm_invalidate_sessions(TPM_HANDLE handle) { TPM_SESSION_DATA *session; int i; for (i = 0; i < TPM_MAX_SESSIONS; i++) { session = &tpmData.stany.data.sessions[i]; if ((session->type == TPM_ST_OSAP && session->handle == handle) || (session->type == TPM_ST_DSAP && session->handle == handle) || (session->type == TPM_ST_TRANSPORT && session->handle == handle)) memset(session, 0, sizeof(*session)); } } TPM_RESULT TPM_KeyControlOwner(TPM_KEY_HANDLE keyHandle, TPM_PUBKEY pubKey, UINT32 bitName, BOOL bitValue, TPM_AUTH *auth1) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_PUBKEY pubKey2; TPM_DIGEST keyDigest, keyDigest2; info("TPM_KeyControlOwner()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* verify public key */ if (tpm_compute_pubkey_digest(&pubKey, &keyDigest)) { debug("tpm_compute_pubkey_digest() failed"); return TPM_FAIL; } if (tpm_extract_pubkey(key, &pubKey2)) { debug("tpm_extraxt_pubkey() failed."); return TPM_FAIL; } if (tpm_compute_pubkey_digest(&pubKey2, &keyDigest2)) { debug("tpm_compute_pubkey_digest() failed"); free_TPM_PUBKEY(pubKey2); return TPM_FAIL; } free_TPM_PUBKEY(pubKey2); if (memcmp(&keyDigest, &keyDigest2, sizeof(TPM_DIGEST)) != 0) return TPM_BAD_PARAMETER; /* get bit name */ debug("bitName = %d", bitName); if (bitName & TPM_KEY_CONTROL_OWNER_EVICT) { if (bitValue) { int i, num = 0; for (i = 0; i < TPM_MAX_KEYS; i++) { if (!tpmData.permanent.data.keys[i].payload || !(tpmData.permanent.data.keys[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) num++; } if (num < 2) return TPM_NOSPACE; if (key->parentPCRStatus || (key->keyFlags & TPM_KEY_FLAG_VOLATILE)) return TPM_BAD_PARAMETER; key->keyControl |= TPM_KEY_CONTROL_OWNER_EVICT; } else { key->keyControl &= ~TPM_KEY_CONTROL_OWNER_EVICT; } } else { return TPM_BAD_MODE; } return TPM_SUCCESS; } 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; } 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 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 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; } 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; } ================================================ FILE: tpm/tpm_counter.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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 472 2011-11-12 09:00:22Z 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++; memcpy(count, counter, sizeof(TPM_COUNTER_VALUE)); 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; } ================================================ FILE: tpm/tpm_credentials.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_credentials.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_marshalling.h" #include "tpm_data.h" #include "crypto/sha1.h" /* * Credential Handling ([TPM_Part3], Section 14) * There are two create EK commands. The first matches the 1.1 functionality. * The second provides the mechanism to enable revokeEK and provides * FIPS 140-2 compatibility. */ TPM_RESULT tpm_get_pubek(TPM_PUBKEY *pubEndorsementKey) { UINT32 key_length; if (!tpmData.permanent.data.endorsementKey.size) return TPM_NO_ENDORSEMENT; /* setup TPM_PUBKEY structure */ key_length = tpmData.permanent.data.endorsementKey.size; pubEndorsementKey->pubKey.keyLength = key_length >> 3; pubEndorsementKey->pubKey.key = tpm_malloc(pubEndorsementKey->pubKey.keyLength); if (pubEndorsementKey->pubKey.key == NULL) return TPM_FAIL; tpm_rsa_export_modulus(&tpmData.permanent.data.endorsementKey, pubEndorsementKey->pubKey.key, NULL); pubEndorsementKey->algorithmParms.algorithmID = TPM_ALG_RSA; pubEndorsementKey->algorithmParms.encScheme = TPM_ES_RSAESOAEP_SHA1_MGF1; pubEndorsementKey->algorithmParms.sigScheme = TPM_SS_NONE; pubEndorsementKey->algorithmParms.parms.rsa.keyLength = key_length; pubEndorsementKey->algorithmParms.parms.rsa.numPrimes = 2; pubEndorsementKey->algorithmParms.parms.rsa.exponentSize = 0; pubEndorsementKey->algorithmParms.parms.rsa.exponent = NULL; pubEndorsementKey->algorithmParms.parmSize = 12; return TPM_SUCCESS; } TPM_RESULT TPM_CreateEndorsementKeyPair(TPM_NONCE *antiReplay, TPM_KEY_PARMS *keyInfo, TPM_PUBKEY *pubEndorsementKey, TPM_DIGEST *checksum) { info("TPM_CreateEndorsementKeyPair()"); return TPM_DISABLED_CMD; } TPM_RESULT TPM_CreateRevocableEK(TPM_NONCE *antiReplay, TPM_KEY_PARMS *keyInfo, BOOL generateReset, TPM_NONCE *inputEKreset, TPM_PUBKEY *pubEndorsementKey, TPM_DIGEST *checksum, TPM_NONCE *outputEKreset) { TPM_RESULT res; info("TPM_CreateRevocableEK()"); /* verify key parameters */ if (tpmData.permanent.data.endorsementKey.size > 0) return TPM_DISABLED_CMD; if (keyInfo->algorithmID != TPM_ALG_RSA || keyInfo->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || keyInfo->sigScheme != TPM_SS_NONE || keyInfo->parmSize == 0 || keyInfo->parms.rsa.keyLength != 2048 || keyInfo->parms.rsa.numPrimes != 2 || keyInfo->parms.rsa.exponentSize != 0) return TPM_BAD_KEY_PROPERTY; /* create endorsement key */ if (tpm_rsa_generate_key(&tpmData.permanent.data.endorsementKey, keyInfo->parms.rsa.keyLength)) return TPM_FAIL; /* return PUBEK */ res = tpm_get_pubek(pubEndorsementKey); if (res != TPM_SUCCESS) { tpm_rsa_release_private_key(&tpmData.permanent.data.endorsementKey); tpmData.permanent.data.endorsementKey.size = 0; return res; } /* compute checksum */ if (tpm_compute_pubkey_checksum(antiReplay, pubEndorsementKey, checksum)) { tpm_free(pubEndorsementKey->pubKey.key); tpm_rsa_release_private_key(&tpmData.permanent.data.endorsementKey); tpmData.permanent.data.endorsementKey.size = 0; return TPM_FAIL; } tpmData.permanent.flags.enableRevokeEK = TRUE; tpmData.permanent.flags.CEKPUsed = TRUE; if (generateReset) { tpm_get_random_bytes(tpmData.permanent.data.ekReset.nonce, sizeof(tpmData.permanent.data.ekReset.nonce)); } else { memcpy(&tpmData.permanent.data.ekReset, inputEKreset, sizeof(TPM_NONCE)); } memcpy(outputEKreset, &tpmData.permanent.data.ekReset, sizeof(TPM_NONCE)); /* Create TPM_PERMANENT_DATA->TPM_DAA_TPM_SEED from the TPM RNG */ tpm_get_random_bytes(tpmData.permanent.data.tpmDAASeed.nonce, sizeof(tpmData.permanent.data.tpmDAASeed.nonce)); return TPM_SUCCESS; } TPM_RESULT TPM_RevokeTrust(TPM_NONCE *ekReset) { info("TPM_RevokeTrust()"); if (!tpmData.permanent.flags.enableRevokeEK) return TPM_FAIL; if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; if (memcmp(ekReset, &tpmData.permanent.data.ekReset, sizeof(TPM_NONCE))) return TPM_AUTHFAIL; tpm_owner_clear(); tpm_rsa_release_private_key(&tpmData.permanent.data.endorsementKey); tpmData.permanent.data.endorsementKey.size = 0; /* Invalidate TPM_PERMANENT_DATA->tpmDAASeed */ memset(tpmData.permanent.data.tpmDAASeed.nonce, 0, sizeof(tpmData.permanent.data.tpmDAASeed.nonce)); return TPM_SUCCESS; } TPM_RESULT TPM_ReadPubek(TPM_NONCE *antiReplay, TPM_PUBKEY *pubEndorsementKey, TPM_DIGEST *checksum) { TPM_RESULT res; info("TPM_ReadPubek()"); if (!tpmData.permanent.flags.readPubek) return TPM_DISABLED_CMD; /* get PUBEK */ res = tpm_get_pubek(pubEndorsementKey); if (res != TPM_SUCCESS) return res; /* compute checksum */ if (tpm_compute_pubkey_checksum(antiReplay, pubEndorsementKey, checksum)) { tpm_free(pubEndorsementKey->pubKey.key); return TPM_FAIL; } return TPM_SUCCESS; } TPM_RESULT TPM_DisablePubekRead(TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_DisablePubekRead()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; tpmData.permanent.flags.readPubek = FALSE; return TPM_SUCCESS; } TPM_RESULT TPM_OwnerReadInternalPub(TPM_KEY_HANDLE keyHandle, TPM_AUTH *auth1, TPM_PUBKEY *publicPortion) { TPM_RESULT res; TPM_KEY_DATA *srk = &tpmData.permanent.data.srk; info("TPM_OwnerReadInternalPub()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (keyHandle == TPM_KH_EK) { return tpm_get_pubek(publicPortion); } else if (keyHandle == TPM_KH_SRK) { publicPortion->pubKey.keyLength = srk->key.size >> 3; publicPortion->pubKey.key = tpm_malloc(publicPortion->pubKey.keyLength); if (publicPortion->pubKey.key == NULL) return TPM_FAIL; tpm_rsa_export_modulus(&srk->key, publicPortion->pubKey.key, NULL); publicPortion->algorithmParms.algorithmID = TPM_ALG_RSA; publicPortion->algorithmParms.encScheme = srk->encScheme; publicPortion->algorithmParms.sigScheme = srk->sigScheme; publicPortion->algorithmParms.parms.rsa.keyLength = srk->key.size; publicPortion->algorithmParms.parms.rsa.numPrimes = 2; publicPortion->algorithmParms.parms.rsa.exponentSize = 0; publicPortion->algorithmParms.parms.rsa.exponent = NULL; publicPortion->algorithmParms.parmSize = 12; return TPM_SUCCESS; } else { return TPM_BAD_PARAMETER; } } ================================================ FILE: tpm/tpm_crypto.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_crypto.c 444 2010-06-12 09:14:18Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "crypto/sha1.h" #include "crypto/hmac.h" #include "crypto/rc4.h" #include "tpm_marshalling.h" /* * Cryptographic Functions ([TPM_Part3], Section 13) */ static tpm_sha1_ctx_t sha1_ctx; static BOOL sha1_ctx_valid = FALSE; TPM_RESULT TPM_SHA1Start(UINT32 *maxNumBytes) { info("TPM_SHA1Start()"); tpm_sha1_init(&sha1_ctx); sha1_ctx_valid = TRUE; /* this limit was arbitrarily chosen */ *maxNumBytes = 2048; return TPM_SUCCESS; } TPM_RESULT TPM_SHA1Update(UINT32 numBytes, BYTE *hashData) { info("TPM_SHA1Update()"); if (!sha1_ctx_valid) return TPM_SHA_THREAD; tpm_sha1_update(&sha1_ctx, hashData, numBytes); return TPM_SUCCESS; } TPM_RESULT TPM_SHA1Complete(UINT32 hashDataSize, BYTE *hashData, TPM_DIGEST *hashValue) { info("TPM_SHA1Complete()"); if (!sha1_ctx_valid) return TPM_SHA_THREAD; sha1_ctx_valid = FALSE; tpm_sha1_update(&sha1_ctx, hashData, hashDataSize); tpm_sha1_final(&sha1_ctx, hashValue->digest); return TPM_SUCCESS; } TPM_RESULT TPM_SHA1CompleteExtend(TPM_PCRINDEX pcrNum, UINT32 hashDataSize, BYTE *hashData, TPM_DIGEST *hashValue, TPM_PCRVALUE *outDigest) { TPM_RESULT res; info("TPM_SHA1CompleteExtend()"); res = TPM_SHA1Complete(hashDataSize, hashData, hashValue); if (res != TPM_SUCCESS) return res; return TPM_Extend(pcrNum, hashValue, outDigest); } TPM_RESULT tpm_verify(TPM_PUBKEY_DATA *key, TPM_AUTH *auth, BOOL isInfo, BYTE *data, UINT32 dataSize, BYTE *sig, UINT32 sigSize) { if (sigSize != key->key.size >> 3) return TPM_BAD_SIGNATURE; if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { /* use signature scheme PKCS1_SHA1_RAW */ if (dataSize != 20) return TPM_BAD_PARAMETER; if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1_RAW, data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE; } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_DER) { /* use signature scheme PKCS1_DER */ if ((dataSize + 11) > (UINT32)(key->key.size >> 3) || dataSize == 0) return TPM_BAD_PARAMETER; if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_DER, data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE; } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && !isInfo) { /* use signature scheme PKCS1_SHA1 and TPM_SIGN_INFO container */ BYTE buf[dataSize + 30]; if ((dataSize + 30) > (UINT32)(key->key.size >> 3) || dataSize == 0) return TPM_BAD_PARAMETER; /* setup TPM_SIGN_INFO structure */ memcpy(&buf[0], "\x00\x05SIGN", 6); memcpy(&buf[6], auth->nonceOdd.nonce, 20); buf[26] = (dataSize >> 24) & 0xff; buf[27] = (dataSize >> 16) & 0xff; buf[28] = (dataSize >> 8) & 0xff; buf[29] = (dataSize ) & 0xff; memcpy(&buf[30], data, dataSize); if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1, data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE; } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && isInfo) { /* TPM_SIGN_INFO structure is already set up */ if (dataSize > (UINT32)(key->key.size >> 3) || dataSize == 0) return TPM_BAD_PARAMETER; if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1, data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE; } else { return TPM_INVALID_KEYUSAGE; } return TPM_SUCCESS; } TPM_RESULT tpm_sign(TPM_KEY_DATA *key, TPM_AUTH *auth, BOOL isInfo, BYTE *areaToSign, UINT32 areaToSignSize, BYTE **sig, UINT32 *sigSize) { if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { /* use signature scheme PKCS1_SHA1_RAW */ if (areaToSignSize != 20) return TPM_BAD_PARAMETER; *sigSize = key->key.size >> 3; *sig = tpm_malloc(*sigSize); if (*sig == NULL || tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1_RAW, areaToSign, areaToSignSize, *sig)) { tpm_free(*sig); return TPM_FAIL; } } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_DER) { /* use signature scheme PKCS1_DER */ if ((areaToSignSize + 11) > (UINT32)(key->key.size >> 3) || areaToSignSize == 0) return TPM_BAD_PARAMETER; *sigSize = key->key.size >> 3; *sig = tpm_malloc(*sigSize); if (*sig == NULL || tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_DER, areaToSign, areaToSignSize, *sig)) { tpm_free(*sig); return TPM_FAIL; } } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && !isInfo) { /* use signature scheme PKCS1_SHA1 and TPM_SIGN_INFO container */ BYTE buf[areaToSignSize + 30]; if ((areaToSignSize + 30) > (UINT32)(key->key.size >> 3) || areaToSignSize == 0) return TPM_BAD_PARAMETER; *sigSize = key->key.size >> 3; *sig = tpm_malloc(*sigSize); if (*sig == NULL) return TPM_FAIL; /* setup TPM_SIGN_INFO structure */ memcpy(&buf[0], "\x00\x05SIGN", 6); memcpy(&buf[6], auth->nonceOdd.nonce, 20); buf[26] = (areaToSignSize >> 24) & 0xff; buf[27] = (areaToSignSize >> 16) & 0xff; buf[28] = (areaToSignSize >> 8) & 0xff; buf[29] = (areaToSignSize ) & 0xff; memcpy(&buf[30], areaToSign, areaToSignSize); if (tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1, buf, areaToSignSize + 30, *sig)) { tpm_free(*sig); return TPM_FAIL; } } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && isInfo) { /* TPM_SIGN_INFO structure is already set up */ if (areaToSignSize > (UINT32)(key->key.size >> 3) || areaToSignSize == 0) return TPM_BAD_PARAMETER; *sigSize = key->key.size >> 3; *sig = tpm_malloc(*sigSize); if (*sig == NULL) return TPM_FAIL; if (tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1, areaToSign, areaToSignSize, *sig)) { tpm_free(*sig); return TPM_FAIL; } } else { return TPM_INVALID_KEYUSAGE; } return TPM_SUCCESS; } TPM_RESULT TPM_Sign(TPM_KEY_HANDLE keyHandle, UINT32 areaToSignSize, BYTE *areaToSign, TPM_AUTH *auth1, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; info("TPM_Sign()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY) return TPM_INVALID_KEYUSAGE; /* sign data */ return tpm_sign(key, auth1, FALSE, areaToSign, areaToSignSize, sig, sigSize); } void tpm_get_random_bytes(void *buf, size_t nbytes) { if (tpmConf & TPM_CONF_USE_INTERNAL_PRNG) { tpm_rc4_ctx_t ctx; tpm_rc4_init(&ctx, tpmData.permanent.data.rngState, sizeof(tpmData.permanent.data.rngState)); tpm_rc4_crypt(&ctx, buf, buf, nbytes); tpm_rc4_crypt(&ctx, tpmData.permanent.data.rngState, tpmData.permanent.data.rngState, sizeof(tpmData.permanent.data.rngState)); } else { tpm_get_extern_random_bytes(buf, nbytes); } } TPM_RESULT TPM_GetRandom(UINT32 bytesRequested, UINT32 *randomBytesSize, BYTE **randomBytes) { info("TPM_GetRandom()"); *randomBytesSize = (bytesRequested < 2048) ? bytesRequested : 2048; *randomBytes = tpm_malloc(*randomBytesSize); if (*randomBytes == NULL) return TPM_SIZE; tpm_get_random_bytes(*randomBytes, *randomBytesSize); return TPM_SUCCESS; } TPM_RESULT TPM_StirRandom(UINT32 dataSize, BYTE *inData) { info("TPM_StirRandom()"); UINT32 i, length = sizeof(tpmData.permanent.data.rngState); while (dataSize > length) { for (i = 0; i < length; i++) { tpmData.permanent.data.rngState[i] ^= *inData++; } dataSize -= length; } for (i = 0; i < dataSize; i++) { tpmData.permanent.data.rngState[i] ^= *inData++; } return TPM_SUCCESS; } TPM_RESULT TPM_CertifyKey(TPM_KEY_HANDLE certHandle, TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_CERTIFY_INFO *certifyInfo, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *cert, *key; tpm_sha1_ctx_t sha1_ctx; BYTE *buf, *p; UINT32 length; info("TPM_CertifyKey()"); /* get keys */ cert = tpm_get_key(certHandle); if (cert == NULL) return TPM_INVALID_KEYHANDLE; key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth2->authHandle != TPM_INVALID_HANDLE || cert->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, cert->usageAuth, certHandle); if (res != TPM_SUCCESS) return res; } if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth2, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res; } /* verify key usage */ if (cert->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1 && cert->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO) return TPM_BAD_SCHEME; if (cert->keyUsage == TPM_KEY_IDENTITY && (key->keyFlags & TPM_KEY_FLAG_MIGRATABLE) && !(key->keyFlags & TPM_KEY_FLAG_AUTHORITY)) return TPM_MIGRATEFAIL; if (key->keyFlags & TPM_KEY_FLAG_HAS_PCR) { if (!(key->keyFlags & TPM_KEY_FLAG_PCR_IGNORE)) { TPM_DIGEST digest; res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &key->pcrInfo.digestAtRelease, sizeof(TPM_DIGEST))) return TPM_WRONGPCRVAL; if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG && !(key->pcrInfo.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; } /* if sizeOfSelect is two use a TPM_CERTIFY_INFO structure ... */ if (key->pcrInfo.releasePCRSelection.sizeOfSelect == 2) { certifyInfo->tag = 0x0101; certifyInfo->fill = 0x0000; certifyInfo->migrationAuthoritySize = 0; memcpy(&certifyInfo->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO)); memset(&certifyInfo->PCRInfo.digestAtCreation, 0, sizeof(TPM_DIGEST)); certifyInfo->PCRInfoSize = sizeof(TPM_PCR_INFO); /* ... otherwise use a TPM_CERTIFY_INFO2 structure */ } else { certifyInfo->tag = TPM_TAG_CERTIFY_INFO2; certifyInfo->fill = 0x0000; certifyInfo->migrationAuthoritySize = 0; memcpy(&certifyInfo->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO)); certifyInfo->PCRInfoSize = sizeof(TPM_PCR_INFO); } } else { /* setup TPM_CERTIFY_INFO structure */ certifyInfo->tag = 0x0101; certifyInfo->fill = 0x0000; certifyInfo->migrationAuthoritySize = 0; certifyInfo->PCRInfoSize = 0; } /* setup CERTIFY_INFO[2] structure */ certifyInfo->keyUsage = key->keyUsage; certifyInfo->keyFlags = key->keyFlags & TPM_KEY_FLAG_MASK; certifyInfo->authDataUsage = key->authDataUsage; certifyInfo->parentPCRStatus = key->parentPCRStatus; if (tpm_setup_key_parms(key, &certifyInfo->algorithmParms)) return TPM_FAIL; memcpy(&certifyInfo->data, antiReplay, sizeof(TPM_NONCE)); /* compute pubKeyDigest */ length = key->key.size >> 3; buf = tpm_malloc(length); if (buf == NULL) { free_TPM_KEY_PARMS(certifyInfo->algorithmParms); return TPM_FAIL; } tpm_rsa_export_modulus(&key->key, buf, NULL); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, length); tpm_sha1_final(&sha1_ctx, certifyInfo->pubkeyDigest.digest); tpm_free(buf); /* compute the digest of the CERTIFY_INFO[2] structure and sign it */ length = sizeof_TPM_CERTIFY_INFO((*certifyInfo)); p = buf = tpm_malloc(length); if (buf == NULL || tpm_marshal_TPM_CERTIFY_INFO(&p, &length, certifyInfo)) { free_TPM_KEY_PARMS(certifyInfo->algorithmParms); return TPM_FAIL; } length = sizeof_TPM_CERTIFY_INFO((*certifyInfo)); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, length); tpm_sha1_final(&sha1_ctx, buf); res = tpm_sign(cert, auth1, FALSE, buf, SHA1_DIGEST_LENGTH, outData, outDataSize); tpm_free(buf); if (res != TPM_SUCCESS) { free_TPM_KEY_PARMS(certifyInfo->algorithmParms); return res; } return TPM_SUCCESS; } TPM_RESULT TPM_CertifyKey2(TPM_KEY_HANDLE keyHandle, TPM_KEY_HANDLE certHandle, TPM_DIGEST *migrationPubDigest, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_CERTIFY_INFO *certifyInfo, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *cert, *key; tpm_sha1_ctx_t sha1_ctx; BYTE *buf, *p; UINT32 length; info("TPM_CertifyKey2()"); /* get keys */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; cert = tpm_get_key(certHandle); if (cert == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth2->authHandle != TPM_INVALID_HANDLE || cert->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth2, cert->usageAuth, certHandle); if (res != TPM_SUCCESS) return res; } if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res; } /* verify key usage */ if (cert->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) return TPM_BAD_SCHEME; if (cert->keyUsage == TPM_KEY_IDENTITY && (key->keyFlags & TPM_KEY_FLAG_MIGRATABLE) && !(key->keyFlags & TPM_KEY_FLAG_AUTHORITY)) return TPM_MIGRATEFAIL; if (key->keyFlags & TPM_KEY_FLAG_HAS_PCR) { if (!(key->keyFlags & TPM_KEY_FLAG_PCR_IGNORE)) { TPM_DIGEST digest; res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &key->pcrInfo.digestAtRelease, sizeof(TPM_DIGEST))) return TPM_WRONGPCRVAL; if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG && !(key->pcrInfo.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; } memcpy(&certifyInfo->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO)); certifyInfo->PCRInfoSize = sizeof(certifyInfo->PCRInfo); } else { certifyInfo->PCRInfoSize = 0; } /* setup migration authority values */ if (key->payload == TPM_PT_MIGRATE_RESTRICTED || key->payload == TPM_PT_MIGRATE_EXTERNAL) { TPM_PUBKEY pubKey; TPM_DIGEST keyDigest; BYTE buf[SHA1_DIGEST_LENGTH]; tpm_hmac_ctx_t hmac_ctx; tpm_sha1_ctx_t sha1_ctx; /* compute digest of public key */ if (tpm_extract_pubkey(key, &pubKey) != 0) { debug("tpm_extract_pubkey() failed"); return TPM_FAIL; } if (tpm_compute_pubkey_digest(&pubKey, &keyDigest) != 0) { debug("tpm_compute_pubkey_digest() failed."); free_TPM_PUBKEY(pubKey); return TPM_FAIL; } free_TPM_PUBKEY(pubKey); /* verify migration authorization */ buf[0] = (TPM_TAG_CMK_MIGAUTH >> 8) & 0xff; buf[1] = TPM_TAG_CMK_MIGAUTH & 0xff; tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&hmac_ctx, buf, 2); tpm_hmac_update(&hmac_ctx, migrationPubDigest->digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&hmac_ctx, keyDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&hmac_ctx, buf); if (memcmp(key->migrationAuth, buf, sizeof(TPM_SECRET)) != 0) return TPM_MA_SOURCE; /* compute migrationAuthority */ certifyInfo->migrationAuthoritySize = SHA1_DIGEST_LENGTH; certifyInfo->migrationAuthority = tpm_malloc(certifyInfo->migrationAuthoritySize); if (certifyInfo->migrationAuthority == NULL) return TPM_NOSPACE; tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, migrationPubDigest->digest, sizeof(TPM_DIGEST)); buf[0] = key->payload; tpm_sha1_update(&sha1_ctx, buf, 1); tpm_sha1_final(&sha1_ctx, certifyInfo->migrationAuthority); certifyInfo->payloadType = key->payload; } else { certifyInfo->migrationAuthoritySize = 0; certifyInfo->migrationAuthority = 0; certifyInfo->payloadType = TPM_PT_ASYM; } /* setup CERTIFY_INFO2 structure */ certifyInfo->tag = TPM_TAG_CERTIFY_INFO2; certifyInfo->fill = 0x0000; certifyInfo->keyUsage = key->keyUsage; certifyInfo->keyFlags = key->keyFlags & TPM_KEY_FLAG_MASK; certifyInfo->authDataUsage = key->authDataUsage; certifyInfo->parentPCRStatus = key->parentPCRStatus; if (tpm_setup_key_parms(key, &certifyInfo->algorithmParms)) return TPM_FAIL; memcpy(&certifyInfo->data, antiReplay, sizeof(TPM_NONCE)); /* compute pubKeyDigest */ length = key->key.size >> 3; buf = tpm_malloc(length); if (buf == NULL) { free_TPM_KEY_PARMS(certifyInfo->algorithmParms); return TPM_FAIL; } tpm_rsa_export_modulus(&key->key, buf, NULL); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, length); tpm_sha1_final(&sha1_ctx, certifyInfo->pubkeyDigest.digest); tpm_free(buf); /* compute the digest of the CERTIFY_INFO[2] structure and sign it */ length = sizeof_TPM_CERTIFY_INFO((*certifyInfo)); p = buf = tpm_malloc(length); if (buf == NULL || tpm_marshal_TPM_CERTIFY_INFO(&p, &length, certifyInfo)) { free_TPM_KEY_PARMS(certifyInfo->algorithmParms); return TPM_FAIL; } length = sizeof_TPM_CERTIFY_INFO((*certifyInfo)); tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, length); tpm_sha1_final(&sha1_ctx, buf); res = tpm_sign(cert, auth2, FALSE, buf, SHA1_DIGEST_LENGTH, outData, outDataSize); tpm_free(buf); if (res != TPM_SUCCESS) { free_TPM_KEY_PARMS(certifyInfo->algorithmParms); return res; } return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_daa.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * 2005-2008 Heiko Stamer * * 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_daa.c 452 2010-07-19 19:05:05Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "tpm_marshalling.h" #include "crypto/sha1.h" #include "crypto/rsa.h" #include "crypto/rc4.h" #include "crypto/hmac.h" #define DAA_LABEL_00 ((uint8_t*)"\x00") #define DAA_LABEL_01 ((uint8_t*)"\x01") #define DAA_LABEL_r0 ((uint8_t*)"r0") #define DAA_LABEL_r1 ((uint8_t*)"r1") #define DAA_LABEL_r2 ((uint8_t*)"r2") UINT32 tpm_get_free_daa_session(void) { UINT32 i; for (i = 0; i < TPM_MAX_SESSIONS_DAA; i++) { if (tpmData.stany.data.sessionsDAA[i].type == TPM_ST_INVALID) { tpmData.stany.data.sessionsDAA[i].type = TPM_ST_DAA; tpmData.stany.data.sessionsDAA[i].handle = INDEX_TO_DAA_HANDLE(i); return INDEX_TO_DAA_HANDLE(i); } } return TPM_INVALID_HANDLE; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error on mismatch */ static TPM_RESULT tpm_daa_verify_digestContext(TPM_DAA_SESSION_DATA *session, tpm_sha1_ctx_t *sha1) { TPM_DIGEST dgt; UINT32 size, len; BYTE *buf, *ptr; tpm_sha1_init(sha1); size = len = sizeof(TPM_DAA_TPM); buf = ptr = tpm_malloc(size); if (buf == NULL) return -1; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_TPM(&ptr, &len, &session->DAA_tpmSpecific)) { tpm_free(buf); return -1; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); size = len = sizeof(TPM_DAA_JOINDATA); buf = ptr = tpm_malloc(size); if (buf == NULL) return -1; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_JOINDATA(&ptr, &len, &session->DAA_joinSession)) { tpm_free(buf); return -1; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); tpm_sha1_final(sha1, dgt.digest); return memcmp(dgt.digest, session->DAA_session.DAA_digestContext.digest, sizeof(TPM_DIGEST)); } /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ static void tpm_daa_update_digestContext(TPM_DAA_SESSION_DATA *session, tpm_sha1_ctx_t *sha1) { UINT32 size, len; BYTE *buf, *ptr; tpm_sha1_init(sha1); /* DAA_tpmSpecific */ size = len = sizeof(TPM_DAA_TPM); buf = ptr = tpm_malloc(size); if (buf == NULL) return; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_TPM(&ptr, &len, &session->DAA_tpmSpecific)) { tpm_free(buf); return; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); /* DAA_joinSession */ size = len = sizeof(TPM_DAA_JOINDATA); buf = ptr = tpm_malloc(size); if (buf == NULL) return; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_JOINDATA(&ptr, &len, &session->DAA_joinSession)) { tpm_free(buf); return; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); tpm_sha1_final(sha1, session->DAA_session.DAA_digestContext.digest); } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) and * return error on mismatch */ static TPM_RESULT tpm_daa_verify_digestContext_sign(TPM_DAA_SESSION_DATA *session, tpm_sha1_ctx_t *sha1) { TPM_DIGEST dgt; UINT32 size, len; BYTE *buf, *ptr; tpm_sha1_init(sha1); size = len = sizeof(TPM_DAA_TPM); buf = ptr = tpm_malloc(size); if (buf == NULL) return -1; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_TPM(&ptr, &len, &session->DAA_tpmSpecific)) { tpm_free(buf); return -1; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); tpm_sha1_final(sha1, dgt.digest); return memcmp(dgt.digest, session->DAA_session.DAA_digestContext.digest, sizeof(TPM_DIGEST)); } /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific) */ static void tpm_daa_update_digestContext_sign(TPM_DAA_SESSION_DATA *session, tpm_sha1_ctx_t *sha1) { UINT32 size, len; BYTE *buf, *ptr; tpm_sha1_init(sha1); size = len = sizeof(TPM_DAA_TPM); buf = ptr = tpm_malloc(size); if (buf == NULL) return; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_TPM(&ptr, &len, &session->DAA_tpmSpecific)) { tpm_free(buf); return; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); tpm_sha1_final(sha1, session->DAA_session.DAA_digestContext.digest); } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error on mismatch */ static TPM_RESULT tpm_daa_verify_digestIssuer(TPM_DAA_SESSION_DATA *session, tpm_sha1_ctx_t *sha1) { TPM_DIGEST dgt; UINT32 size, len; BYTE *buf, *ptr; tpm_sha1_init(sha1); size = len = sizeof(TPM_DAA_ISSUER); buf = ptr = tpm_malloc(size); if (buf == NULL) return -1; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_ISSUER(&ptr, &len, &session->DAA_issuerSettings)) { tpm_free(buf); return -1; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); tpm_sha1_final(sha1, dgt.digest); return memcmp(dgt.digest, session->DAA_tpmSpecific.DAA_digestIssuer.digest, sizeof(TPM_DIGEST)); } /* Set DAA_tpmSpecific->DAA_digestIssuer == SHA-1(DAA_issuerSettings) */ static void tpm_daa_update_digestIssuer(TPM_DAA_SESSION_DATA *session, tpm_sha1_ctx_t *sha1) { UINT32 size, len; BYTE *buf, *ptr; tpm_sha1_init(sha1); size = len = sizeof(TPM_DAA_ISSUER); buf = ptr = tpm_malloc(size); if (buf == NULL) return; memset(buf, 0, size); if (tpm_marshal_TPM_DAA_ISSUER(&ptr, &len, &session->DAA_issuerSettings)) { tpm_free(buf); return; } tpm_sha1_update(sha1, buf, size); tpm_free(buf); tpm_sha1_final(sha1, session->DAA_tpmSpecific.DAA_digestIssuer.digest); } /* Verify that SHA-1(input) == digest and return error !TPM_SUCCESS * on mismatch */ static TPM_RESULT tpm_daa_verify_generic(TPM_DIGEST digest, BYTE *input, UINT32 inputSize, tpm_sha1_ctx_t *sha1) { TPM_DIGEST dgt; tpm_sha1_init(sha1); tpm_sha1_update(sha1, input, inputSize); tpm_sha1_final(sha1, dgt.digest); return memcmp(dgt.digest, digest.digest, sizeof(TPM_DIGEST)); } /* Encryption and decryption of the TPM_DAA_SENSITIVE structure */ static int encrypt_daa(BYTE *iv, UINT32 iv_size, TPM_DAA_SENSITIVE *sensitive, BYTE **enc, UINT32 *enc_size) { UINT32 len; BYTE *ptr; tpm_rc4_ctx_t rc4_ctx; BYTE key[TPM_SYM_KEY_SIZE + iv_size]; /* marshal sensitive */ *enc_size = len = sizeof_TPM_DAA_SENSITIVE((*sensitive)); *enc = ptr = tpm_malloc(len); if (*enc == NULL) return -1; if (tpm_marshal_TPM_DAA_SENSITIVE(&ptr, &len, sensitive)) { tpm_free(*enc); return -1; } /* encrypt sensitive */ memcpy(key, tpmData.permanent.data.daaKey, 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; } static int decrypt_daa(BYTE *iv, UINT32 iv_size, BYTE *enc, UINT32 enc_size, TPM_DAA_SENSITIVE *sensitive, BYTE **buf) { UINT32 len; BYTE *ptr; tpm_rc4_ctx_t rc4_ctx; BYTE key[TPM_SYM_KEY_SIZE + iv_size]; /* decrypt sensitive */ len = enc_size, *buf = ptr = tpm_malloc(len); if (ptr == NULL) return -1; memcpy(key, tpmData.permanent.data.daaKey, 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, ptr, enc_size); /* unmarshal sensitive */ if (tpm_unmarshal_TPM_DAA_SENSITIVE(&ptr, &len, sensitive)) { tpm_free(*buf); return -1; } return 0; } /* Computation of the HMAC which protects the integrity of the TPM_DAA_BLOB */ static int compute_daa_digest(TPM_DAA_BLOB *daaBlob, TPM_DIGEST *digest) { BYTE *buf, *ptr; UINT32 len; tpm_hmac_ctx_t hmac_ctx; len = sizeof_TPM_DAA_BLOB((*daaBlob)); buf = ptr = tpm_malloc(len); if (buf == NULL) return -1; if (tpm_marshal_TPM_DAA_BLOB(&ptr, &len, daaBlob)) { tpm_free(buf); return -1; } memset(&buf[22], 0, sizeof(TPM_DIGEST)); tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.daaProof.nonce, sizeof(tpmData.permanent.data.daaProof.nonce)); tpm_hmac_update(&hmac_ctx, buf, sizeof_TPM_DAA_BLOB((*daaBlob))); tpm_hmac_final(&hmac_ctx, digest->digest); tpm_free(buf); return 0; } /* * DAA commands ([TPM_Part3], Section 26) * Operations that are necessary to setup a TPM for DAA, execute the * JOIN process, and execute the SIGN process. */ #define SCRATCH_SIZE 256 TPM_RESULT TPM_DAA_Join(TPM_HANDLE handle, BYTE stage, UINT32 inputSize0, BYTE *inputData0, UINT32 inputSize1, BYTE *inputData1, TPM_AUTH *auth1, TPM_COMMAND_CODE *ordinal, UINT32 *outputSize, BYTE **outputData) { BYTE scratch[SCRATCH_SIZE]; TPM_DAA_SESSION_DATA *session = NULL; TPM_RESULT res; UINT32 cnt, len; tpm_sha1_ctx_t sha1; tpm_rsa_public_key_t key; BYTE *signedData = NULL, *signatureValue = NULL, *DAA_generic_gamma = NULL, *DAA_generic_R0 = NULL, *DAA_generic_R1 = NULL, *DAA_generic_n = NULL, *DAA_generic_S0 = NULL, *DAA_generic_S1 = NULL, *ptr; tpm_bn_t X, Y, Z, n, f, q, f0, f1, w1, w, gamma, r0, r1, r2, r3, r, s0, s1, s12, s2, s3, E, E1, u2, u3, v0, v10, v1, tmp; size_t size; BYTE mgf1_seed[2 + sizeof(TPM_DIGEST)]; TPM_DAA_BLOB blob; TPM_DAA_SENSITIVE sensitive; info("TPM_DAA_Join()"); debug("handle = %.8x, stage = %d", handle, stage); debug("stany.data.currentDAA = %.8x", tpmData.stany.data.currentDAA); /* Initalize internal scratch pad */ memset(scratch, 0, SCRATCH_SIZE); /* Verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* Verify and initalize the session, for all stages greater than zero. */ if (stage > 0) { if ((HANDLE_TO_INDEX(handle) >= TPM_MAX_SESSIONS_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].type != TPM_ST_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].handle != handle)) { /* Probe, whether the handle from stany.data.currentDAA is valid. */ handle = tpmData.stany.data.currentDAA; if ((HANDLE_TO_INDEX(handle) >= TPM_MAX_SESSIONS_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].type != TPM_ST_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].handle != handle)) return TPM_BAD_HANDLE; } session = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)]; } /* TPM_DAA_JOIN [TPM_Part3], Section 26.1, Rev. 85 */ switch (stage) { case 0: { /* Determine that sufficient resources are available to perform a * DAA_Join. Assign session handle for this DAA_Join. */ handle = tpm_get_free_daa_session(); if (handle == TPM_INVALID_HANDLE) return TPM_RESOURCES; session = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)]; /* Set all fields in DAA_issuerSettings = NULL */ memset(&session->DAA_issuerSettings, 0, sizeof(TPM_DAA_ISSUER)); session->DAA_issuerSettings.tag = TPM_TAG_DAA_ISSUER; /* Set all fields in DAA_tpmSpecific = NULL */ memset(&session->DAA_tpmSpecific, 0, sizeof(TPM_DAA_TPM)); session->DAA_tpmSpecific.tag = TPM_TAG_DAA_TPM; /* Set all fields in DAA_session = NULL */ memset(&session->DAA_session, 0, sizeof(TPM_DAA_CONTEXT)); session->DAA_session.tag = TPM_TAG_DAA_CONTEXT; /* Set all fields in DAA_joinSession = NULL */ memset(&session->DAA_joinSession, 0, sizeof(TPM_DAA_JOINDATA)); /* Verify that sizeOf(inputData0) == sizeOf(DAA_tpmSpecific->DAA_count) * and return error TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(session->DAA_tpmSpecific.DAA_count)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Verify that inputData0 > 0, and return TPM_DAA_INPUT_DATA0 on * mismatch */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_UINT32(&ptr, &len, &cnt) || (len != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if (cnt <= 0) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_tpmSpecific->DAA_count = inputData0 */ debug("TPM_DAA_Join() -- set DAA_count := %d", cnt); session->DAA_tpmSpecific.DAA_count = cnt; /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ tpm_daa_update_digestContext(session, &sha1); /* Set DAA_session->DAA_stage = 1 */ session->DAA_session.DAA_stage = 1; /* Assign session handle for DAA_Join */ tpmData.stany.data.currentDAA = handle; debug("TPM_DAA_Join() -- set handle := %.8x", handle); /* Set outputData = new session handle */ *outputSize = sizeof(TPM_HANDLE); if ((*outputData = tpm_malloc(*outputSize)) != NULL) { ptr = *outputData, len = *outputSize; if (tpm_marshal_TPM_HANDLE(&ptr, &len, handle)) { debug("TPM_DAA_Join(): tpm_marshal_TPM_HANDLE() failed."); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } } else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 1: { /* Verify that DAA_session->DAA_stage == 1. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 1) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify that sizeOf(inputData0) == DAA_SIZE_issuerModulus and * return error TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != DAA_SIZE_issuerModulus) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* If DAA_session->DAA_scratch == NULL: */ if (!memcmp(scratch, session->DAA_session.DAA_scratch, sizeof(session->DAA_session.DAA_scratch))) { /* Set DAA_session->DAA_scratch = inputData0 */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); memcpy(session->DAA_session.DAA_scratch, inputData0, inputSize0); /* Set DAA_joinSession->DAA_digest_n0 = * SHA-1(DAA_session->DAA_scratch) */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, session->DAA_session.DAA_scratch, sizeof(session->DAA_session.DAA_scratch)); tpm_sha1_final(&sha1, (BYTE*) &session->DAA_joinSession.DAA_digest_n0); /* Set DAA_tpmSpecific->DAA_rekey = SHA-1(TPM_DAA_TPM_SEED || * DAA_joinSession->DAA_digest_n0) */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &tpmData.permanent.data.tpmDAASeed, sizeof(tpmData.permanent.data.tpmDAASeed)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_joinSession.DAA_digest_n0, sizeof(session->DAA_joinSession.DAA_digest_n0)); tpm_sha1_final(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey); /* Else (If DAA_session->DAA_scratch != NULL): */ } else { /* Set signedData = inputData0 */ signedData = inputData0; /* Verify that sizeOf(inputData1) == DAA_SIZE_issuerModulus and * return error TPM_DAA_INPUT_DATA1 on mismatch */ if (inputSize1 != DAA_SIZE_issuerModulus) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set signatureValue = inputData1 */ signatureValue = inputData1; /* Use the RSA key == [DAA_session->DAA_scratch] to verify that * signatureValue is a signature on signedData, and return error * TPM_DAA_ISSUER_VALIDITY on mismatch */ if (tpm_rsa_import_public_key(&key, RSA_MSB_FIRST, session->DAA_session.DAA_scratch, DAA_SIZE_issuerModulus, NULL, 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_VALIDITY; } if (tpm_rsa_verify(&key, RSA_SSA_PKCS1_SHA1, signedData, inputSize0, signatureValue)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_VALIDITY; } tpm_rsa_release_public_key(&key); /* Set DAA_session->DAA_scratch = signedData */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); memcpy(session->DAA_session.DAA_scratch, inputData0, inputSize0); } /* Decrement DAA_tpmSpecific->DAA_count by 1 (unity) */ session->DAA_tpmSpecific.DAA_count--; /* If DAA_tpmSpecific->DAA_count == 0: */ if (session->DAA_tpmSpecific.DAA_count == 0) { /* Increment DAA_Session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; } /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ tpm_daa_update_digestContext(session, &sha1); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 2: { /* Verify that DAA_session->DAA_stage == 2. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 2) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify that sizeOf(inputData0) == sizeOf(TPM_DAA_ISSUER) and * return error TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(TPM_DAA_ISSUER)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_issuerSettings = inputData0. Verify that all fields in * DAA_issuerSettings are present and return error * TPM_DAA_INPUT_DATA0 if not. */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_TPM_DAA_ISSUER(&ptr, &len, &session->DAA_issuerSettings) || (len != 0) || !(session->DAA_issuerSettings.tag == TPM_TAG_DAA_ISSUER)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Verify that sizeOf(inputData1) == DAA_SIZE_issuerModulus and * return error TPM_DAA_INPUT_DATA1 on mismatch */ if (inputSize1 != DAA_SIZE_issuerModulus) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set signatureValue = inputData1 */ signatureValue = inputData1; /* Set signedData = (DAA_joinSession->DAA_digest_n0 || * DAA_issuerSettings) */ memcpy(scratch, &session->DAA_joinSession.DAA_digest_n0, sizeof(TPM_DIGEST)); memcpy(scratch + sizeof(TPM_DIGEST), inputData0, inputSize0); signedData = scratch; /* Use the RSA key [DAA_session->DAA_scratch] to verify that * signatureValue is a signature on signedData, and return error * TPM_DAA_ISSUER_VALIDITY on mismatch */ if (tpm_rsa_import_public_key(&key, RSA_MSB_FIRST, session->DAA_session.DAA_scratch, DAA_SIZE_issuerModulus, NULL, 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_VALIDITY; } if (tpm_rsa_verify(&key, RSA_SSA_PKCS1_SHA1, signedData, sizeof(TPM_DIGEST) + inputSize0, signatureValue)) { tpm_rsa_release_public_key(&key); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_VALIDITY; } tpm_rsa_release_public_key(&key); /* Set DAA_tpmSpecific->DAA_digestIssuer == SHA-1(DAA_issuerSettings) */ tpm_daa_update_digestIssuer(session, &sha1); /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ tpm_daa_update_digestContext(session, &sha1); /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Set outputData = NULL */ *outputSize = 0; *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 3: { /* Verify that DAA_session->DAA_stage == 3. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 3) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify that sizeOf(inputData0) == sizeOf(DAA_tpmSpecific->DAA_count) * and return error TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(session->DAA_tpmSpecific.DAA_count)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_tpmSpecific->DAA_count = inputData0 */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_UINT32(&ptr, &len, &session->DAA_tpmSpecific.DAA_count) || (len != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Obtain random data from the RNG and store it as * DAA_joinSession->DAA_join_u0 */ tpm_get_random_bytes(session->DAA_joinSession.DAA_join_u0, sizeof(session->DAA_joinSession.DAA_join_u0)); /* Obtain random data from the RNG and store it as * DAA_joinSession->DAA_join_u1 */ tpm_get_random_bytes(session->DAA_joinSession.DAA_join_u1, sizeof(session->DAA_joinSession.DAA_join_u1)); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ tpm_daa_update_digestContext(session, &sha1); /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 4: { /* Verify that DAA_session->DAA_stage == 4. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 4) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_R0 = inputData0 */ DAA_generic_R0 = inputData0; /* Verify that SHA-1(DAA_generic_R0) == * DAA_issuerSettings->DAA_digest_R0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_R0, DAA_generic_R0, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set X = DAA_generic_R0 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_R0); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set f = SHA1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0 ) || * SHA1(DAA_tpmSpecific->DAA_rekey || DAA_tpmSpecific->DAA_count || * 1 ) mod DAA_issuerSettings->DAA_generic_q */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 * bits of f) */ tpm_bn_init(f0), tpm_bn_init(tmp); tpm_bn_ui_pow_ui(tmp, 2, DAA_power0); tpm_bn_mod(f0, f, tmp); /* Set DAA_session->DAA_scratch = (X^f0) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_powm(tmp, X, f0, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(f0), tpm_bn_clear(tmp); tpm_bn_clear(X), tpm_bn_clear(n); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 5: { /* Verify that DAA_session->DAA_stage == 5. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 5) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_R1 = inputData0 */ DAA_generic_R1 = inputData0; /* Verify that SHA-1(DAA_generic_R1) == * DAA_issuerSettings->DAA_digest_R1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_R1, DAA_generic_R1, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set X = DAA_generic_R1 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_R1); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set f = SHA1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0 ) || * SHA1(DAA_tpmSpecific->DAA_rekey || DAA_tpmSpecific->DAA_count || * 1 ) mod DAA_issuerSettings->DAA_generic_q */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Shift f right by DAA_power0 bits (discard the lowest DAA_power0 * bits) and label the result f1 */ tpm_bn_init(f1); tpm_bn_fdiv_q_2exp(f1, f, DAA_power0); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^f1) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, f1, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(f1), tpm_bn_clear(tmp); tpm_bn_clear(X), tpm_bn_clear(n), tpm_bn_clear(Z); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 6: { /* Verify that DAA_session->DAA_stage == 6. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 6) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_S0 = inputData0 */ DAA_generic_S0 = inputData0; /* Verify that SHA-1(DAA_generic_S0) == * DAA_issuerSettings->DAA_digest_S0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_S0, DAA_generic_S0, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set X = DAA_generic_S0 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_S0); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set Y = DAA_joinSession->DAA_join_u0 */ tpm_bn_init(Y); tpm_bn_import(Y, sizeof(session->DAA_joinSession.DAA_join_u0), 1, session->DAA_joinSession.DAA_join_u0); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 7: { /* Verify that DAA_session->DAA_stage == 7. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 7) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_S1 = inputData0 */ DAA_generic_S1 = inputData0; /* Verify that SHA-1(DAA_generic_S1) == * DAA_issuerSettings->DAA_digest_S1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_S1, DAA_generic_S1, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set X = DAA_generic_S1 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_S1); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Y = DAA_joinSession->DAA_join_u1 */ tpm_bn_init(Y); tpm_bn_import(Y, sizeof(session->DAA_joinSession.DAA_join_u1), 1, session->DAA_joinSession.DAA_join_u1); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, &size, 1, tmp); memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch + (sizeof(session->DAA_session.DAA_scratch) - size), &size, 1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set DAA_session->DAA_digest to the SHA-1(DAA_session->DAA_scratch || * DAA_tpmSpecific->DAA_count || DAA_joinSession->DAA_digest_n0) */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, session->DAA_session.DAA_scratch, sizeof(session->DAA_session.DAA_scratch)); ptr = scratch, len = sizeof(scratch); if (tpm_marshal_UINT32(&ptr, &len, session->DAA_tpmSpecific.DAA_count)) { debug("TPM_DAA_Join(): tpm_marshal_UINT32() failed."); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } tpm_sha1_update(&sha1, scratch, sizeof(UINT32)); tpm_sha1_update(&sha1, session->DAA_joinSession.DAA_digest_n0.digest, sizeof(session->DAA_joinSession.DAA_digest_n0.digest)); tpm_sha1_final(&sha1, session->DAA_session.DAA_digest.digest); /* Set outputData = DAA_session->DAA_scratch */ *outputSize = sizeof(session->DAA_session.DAA_scratch); if ((*outputData = tpm_malloc(*outputSize)) != NULL) { memcpy(*outputData, session->DAA_session.DAA_scratch, *outputSize); } else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 8: { /* Verify that DAA_session->DAA_stage == 8. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 8) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify inputSize0 == DAA_SIZE_NE and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != DAA_SIZE_NE) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set NE = decrypt(inputData0, privEK) */ memset(scratch, 0, sizeof(scratch)); if (tpm_rsa_decrypt(&tpmData.permanent.data.endorsementKey, RSA_ES_OAEP_SHA1, inputData0, inputSize0, scratch, &size)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DECRYPT_ERROR; } /* Set outputData = SHA-1(DAA_session->DAA_digest || NE) */ *outputSize = SHA1_DIGEST_LENGTH; if ((*outputData = tpm_malloc(*outputSize)) == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, session->DAA_session.DAA_digest.digest, sizeof(session->DAA_session.DAA_digest.digest)); tpm_sha1_update(&sha1, scratch, size); tpm_sha1_final(&sha1, *outputData); /* Set DAA_session->DAA_digest = NULL */ memset(&session->DAA_session.DAA_digest, 0, sizeof(session->DAA_session.DAA_digest)); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 9: { /* Verify that DAA_session->DAA_stage == 9. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 9) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_R0 = inputData0 */ DAA_generic_R0 = inputData0; /* Verify that SHA-1(DAA_generic_R0) == * DAA_issuerSettings->DAA_digest_R0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_R0, DAA_generic_R0, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain random data from the RNG and store it as * DAA_session->DAA_contextSeed */ tpm_get_random_bytes(session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); /* Obtain DAA_SIZE_r0 bits from MGF1("r0", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r0", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r0); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r0, 1, scratch); /* Set X = DAA_generic_R0 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_R0); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set DAA_session->DAA_scratch = (X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 10: { /* Verify that DAA_session->DAA_stage == 10. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 10) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_R1 = inputData0 */ DAA_generic_R1 = inputData0; /* Verify that SHA-1(DAA_generic_R1) == * DAA_issuerSettings->DAA_digest_R1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_R1, DAA_generic_R1, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r1 bits from MGF1("r1", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r1", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r1); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r1, 1, scratch); /* Set X = DAA_generic_R1 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_R1); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 11: { /* Verify that DAA_session->DAA_stage == 11. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 11) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_S0 = inputData0 */ DAA_generic_S0 = inputData0; /* Verify that SHA-1(DAA_generic_S0) == * DAA_issuerSettings->DAA_digest_S0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_S0, DAA_generic_S0, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r2 bits from MGF1("r2", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r2", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r2); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r2, 1, scratch); /* Set X = DAA_generic_S0 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_S0); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 12: { /* Verify that DAA_session->DAA_stage == 12. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 12) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_S1 = inputData0 */ DAA_generic_S1 = inputData0; /* Verify that SHA-1(DAA_generic_S1) == * DAA_issuerSettings->DAA_digest_S1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_S1, DAA_generic_S1, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r3 bits from MGF1("r3", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r3", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r3); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r3, 1, scratch); /* Set X = DAA_generic_S1 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_S1); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, &size, 1, tmp); *outputSize = (uint32_t)size; tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = DAA_session->DAA_scratch */ if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, session->DAA_session.DAA_scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 13: { /* Verify that DAA_session->DAA_stage == 13. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 13) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_gamma = inputData0 */ DAA_generic_gamma = inputData0; /* Verify that SHA-1(DAA_generic_gamma) == * DAA_issuerSettings->DAA_digest_gamma and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_gamma, DAA_generic_gamma, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Verify that inputSize1 == DAA_SIZE_w and return error * TPM_DAA_INPUT_DATA1 on mismatch */ if (inputSize1 != DAA_SIZE_w) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set w = inputData1 */ tpm_bn_init(w); tpm_bn_import(w, inputSize1, 1, inputData1); /* Set w1 = w^(DAA_issuerSettings->DAA_generic_q) mod * (DAA_generic_gamma) */ tpm_bn_init(gamma); tpm_bn_import(gamma, inputSize0, 1, DAA_generic_gamma); tpm_bn_init(q); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_init(w1); tpm_bn_powm(w1, w, q, gamma); /* If w1 != 1 (unity), return error TPM_DAA_WRONG_W */ if (tpm_bn_cmp_ui(w1, 1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_WRONG_W; } /* Set DAA_session->DAA_scratch = w */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, w); tpm_bn_clear(w), tpm_bn_clear(gamma), tpm_bn_clear(w1), tpm_bn_clear(q); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 14: { /* Verify that DAA_session->DAA_stage == 14. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 14) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_gamma = inputData0 */ DAA_generic_gamma = inputData0; /* Verify that SHA-1(DAA_generic_gamma) == * DAA_issuerSettings->DAA_digest_gamma and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_gamma, DAA_generic_gamma, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set f = SHA-1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0) || SHA-1(DAA_tpmSpecific->DAA_rekey * || DAA_tpmSpecific->DAA_count || 1) mod * DAA_issuerSettings->DAA_generic_q. */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Set E = ((DAA_session->DAA_scratch)^f) mod (DAA_generic_gamma).*/ tpm_bn_init(gamma); tpm_bn_import(gamma, inputSize0, 1, DAA_generic_gamma); tpm_bn_init(w); tpm_bn_import(w, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_init(E); tpm_bn_powm(E, w, f, gamma); /* Set outputData = E */ tpm_bn_export(scratch, &size, 1, E); *outputSize = (uint32_t)size; tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(gamma), tpm_bn_clear(w), tpm_bn_clear(E); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 15: { /* Verify that DAA_session->DAA_stage == 15. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 15) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_gamma = inputData0 */ DAA_generic_gamma = inputData0; /* Verify that SHA-1(DAA_generic_gamma) == * DAA_issuerSettings->DAA_digest_gamma and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_gamma, DAA_generic_gamma, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Obtain DAA_SIZE_r0 bits from MGF1("r0", * DAA_session->DAA_contextSeed), and label them r0 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r0", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r0); tpm_bn_init(r0); tpm_bn_import(r0, DAA_SIZE_r0, 1, scratch); /* Obtain DAA_SIZE_r1 bits from MGF1("r1", * DAA_session->DAA_contextSeed), and label them r1 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r1", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r1); tpm_bn_init(r1); tpm_bn_import(r1, DAA_SIZE_r1, 1, scratch); /* Set r = r0 + 2^DAA_power0 * r1 mod * (DAA_issuerSettings->DAA_generic_q). */ tpm_bn_init(q); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_init(r); tpm_bn_ui_pow_ui(r, 2, DAA_power0); tpm_bn_mul(r, r, r1); tpm_bn_mod(r, r, q); tpm_bn_add(r, r, r0); tpm_bn_mod(r, r, q); /* Set E1 = ((DAA_session->DAA_scratch)^r) mod (DAA_generic_gamma). */ tpm_bn_init(gamma); tpm_bn_import(gamma, inputSize0, 1, DAA_generic_gamma); tpm_bn_init(w); tpm_bn_import(w, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_init(E1); tpm_bn_powm(E1, w, r, gamma); /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Set outputData = E1 */ tpm_bn_export(scratch, &size, 1, E1); *outputSize = (uint32_t)size; tpm_bn_clear(r0), tpm_bn_clear(r1), tpm_bn_clear(q), tpm_bn_clear(r); tpm_bn_clear(gamma), tpm_bn_clear(w), tpm_bn_clear(E1); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 16: { BYTE *NT = NULL; /* Verify that DAA_session->DAA_stage == 16. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 16) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify that inputSize0 == sizeOf(TPM_DIGEST) and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(TPM_DIGEST)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_session->DAA_digest = inputData0 */ memcpy(session->DAA_session.DAA_digest.digest, inputData0, inputSize0); /* Obtain DAA_SIZE_NT bits from the RNG and label them NT */ if ((NT = tpm_malloc(DAA_SIZE_NT)) == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_get_random_bytes(NT, DAA_SIZE_NT); /* Set DAA_session->DAA_digest to the SHA-1(DAA_session->DAA_digest || * NT)*/ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) session->DAA_session.DAA_digest.digest, sizeof(session->DAA_session.DAA_digest.digest)); tpm_sha1_update(&sha1, NT, DAA_SIZE_NT); tpm_sha1_final(&sha1, session->DAA_session.DAA_digest.digest); /* Set outputData = NT */ *outputSize = DAA_SIZE_NT; if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, NT, *outputSize); else { tpm_free(NT); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_free(NT); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 17: { /* Verify that DAA_session->DAA_stage == 17. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 17) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r0 bits from MGF1("r0", * DAA_session->DAA_contextSeed), and label them r0 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r0", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r0); tpm_bn_init(r0); tpm_bn_import(r0, DAA_SIZE_r0, 1, scratch); /* Set f = SHA1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0 ) || * SHA1(DAA_tpmSpecific->DAA_rekey || DAA_tpmSpecific->DAA_count || * 1 ) mod DAA_issuerSettings->DAA_generic_q */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 * bits of f) */ tpm_bn_init(f0); tpm_bn_init(tmp); tpm_bn_ui_pow_ui(tmp, 2, DAA_power0); tpm_bn_mod(f0, f, tmp); /* Set s0 = r0 + (DAA_session->DAA_digest) * f0 in Z */ tpm_bn_init(s0); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s0, tmp, f0); tpm_bn_add(s0, r0, s0); /* Set outputData = s0 */ tpm_bn_export(scratch, &size, 1, s0); *outputSize = (uint32_t)size; tpm_bn_clear(r0), tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(f0); tpm_bn_clear(s0), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 18: { /* Verify that DAA_session->DAA_stage == 18. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 18) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r1 bits from MGF1("r1", * DAA_session->DAA_contextSeed), and label them r1 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r1", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r1); tpm_bn_init(r1); tpm_bn_import(r1, DAA_SIZE_r1, 1, scratch); /* Set f = SHA1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0 ) || * SHA1(DAA_tpmSpecific->DAA_rekey || DAA_tpmSpecific->DAA_count || * 1 ) mod DAA_issuerSettings->DAA_generic_q */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Shift f right by DAA_power0 bits (discard the lowest DAA_power0 * bits) and label the result f1 */ tpm_bn_init(f1); tpm_bn_fdiv_q_2exp(f1, f, DAA_power0); /* Set s1 = r1 + (DAA_session->DAA_digest) * f1 in Z */ tpm_bn_init(s1); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s1, tmp, f1); tpm_bn_add(s1, r1, s1); /* Set outputData = s1 */ tpm_bn_export(scratch, &size, 1, s1); *outputSize = (uint32_t)size; tpm_bn_clear(r1), tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(f1); tpm_bn_clear(s1), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 19: { /* Verify that DAA_session->DAA_stage == 19. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 19) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r2 bits from MGF1("r2", * DAA_session->DAA_contextSeed), and label them r2 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r2", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r2); tpm_bn_init(r2); tpm_bn_import(r2, DAA_SIZE_r2, 1, scratch); /* Set s2 = r2 + (DAA_session->DAA_digest) * * (DAA_joinSession->DAA_join_u0) mod 2^DAA_power1 * (Erase all but the lowest DAA_power1 bits of s2) */ tpm_bn_init(s2); tpm_bn_import(s2, sizeof(session->DAA_joinSession.DAA_join_u0), 1, session->DAA_joinSession.DAA_join_u0); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s2, tmp, s2); tpm_bn_add(s2, r2, s2); tpm_bn_ui_pow_ui(tmp, 2, DAA_power1); tpm_bn_mod(s2, s2, tmp); /* Set DAA_session->DAA_scratch = s2 */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, s2); /* Set outputData = s2 */ tpm_bn_export(scratch, &size, 1, s2); *outputSize = (uint32_t)size; tpm_bn_clear(r2), tpm_bn_clear(s2), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 20: { /* Verify that DAA_session->DAA_stage == 20. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 20) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r2 bits from MGF1("r2", * DAA_session->DAA_contextSeed), and label them r2 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r2", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r2); tpm_bn_init(r2); tpm_bn_import(r2, DAA_SIZE_r2, 1, scratch); /* Set s12 = r2 + (DAA_session->DAA_digest) * * (DAA_joinSession->DAA_join_u0) */ tpm_bn_init(s12); tpm_bn_import(s12, sizeof(session->DAA_joinSession.DAA_join_u0), 1, session->DAA_joinSession.DAA_join_u0); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s12, tmp, s12); tpm_bn_add(s12, r2, s12); /* Shift s12 right by DAA_power1 bit (discard the lowest DAA_power1 * bits). */ tpm_bn_fdiv_q_2exp(s12, s12, DAA_power1); /* Set DAA_session->DAA_scratch = s12 */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, s12); tpm_bn_clear(r2), tpm_bn_clear(s12), tpm_bn_clear(tmp); /* Set outputData = DAA_session->DAA_digest */ *outputSize = sizeof(session->DAA_session.DAA_digest.digest); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, session->DAA_session.DAA_digest.digest, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 21: { /* Verify that DAA_session->DAA_stage == 21. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 21) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r3 bits from MGF1("r3", * DAA_session->DAA_contextSeed), and label them r3 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r3", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r3); tpm_bn_init(r3); tpm_bn_import(r3, DAA_SIZE_r3, 1, scratch); /* Set s3 = r3 + (DAA_session->DAA_digest) * * (DAA_joinSession->DAA_join_u1) + (DAA_session->DAA_scratch). */ tpm_bn_init(s3); tpm_bn_import(s3, sizeof(session->DAA_joinSession.DAA_join_u1), 1, session->DAA_joinSession.DAA_join_u1); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s3, tmp, s3); tpm_bn_add(s3, r3, s3); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_add(s3, s3, tmp); /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Set outputData = s3 */ tpm_bn_export(scratch, &size, 1, s3); *outputSize = (uint32_t)size; tpm_bn_clear(r3), tpm_bn_clear(s3), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 22: { /* Verify that DAA_session->DAA_stage == 22. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 22) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify inputSize0 == DAA_SIZE_v0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != DAA_SIZE_v0) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set u2 = inputData0 */ tpm_bn_init(u2); tpm_bn_import(u2, DAA_SIZE_v0, 1, inputData0); /* Set v0 = u2 + (DAA_joinSession->DAA_join_u0) mod 2^DAA_power1 * (Erase all but the lowest DAA_power1 bits of v0). */ tpm_bn_init(v0); tpm_bn_import(v0, sizeof(session->DAA_joinSession.DAA_join_u0), 1, session->DAA_joinSession.DAA_join_u0); tpm_bn_add(v0, u2, v0); tpm_bn_init(tmp); tpm_bn_ui_pow_ui(tmp, 2, DAA_power1); tpm_bn_mod(v0, v0, tmp); /* Set DAA_tpmSpecific->DAA_digest_v0 = SHA-1(v0) */ tpm_bn_export(scratch, &size, 1, v0); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) scratch, size); tpm_sha1_final(&sha1, session->DAA_tpmSpecific.DAA_digest_v0.digest); /* Set v10 = u2 + (DAA_joinSession->DAA_join_u0) in Z */ tpm_bn_init(v10); tpm_bn_import(v10, sizeof(session->DAA_joinSession.DAA_join_u0), 1, session->DAA_joinSession.DAA_join_u0); tpm_bn_add(v10, u2, v10); /* Shift v10 right by DAA_power1 bits (erase the lowest DAA_power1 * bits). */ tpm_bn_fdiv_q_2exp(v10, v10, DAA_power1); /* Set DAA_session->DAA_scratch = v10 */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, v10); tpm_bn_clear(u2), tpm_bn_clear(v0), tpm_bn_clear(tmp), tpm_bn_clear(v10); /* Set outputData */ memset(&blob, 0, sizeof(blob)); /* Fill in TPM_DAA_BLOB with a type of TPM_RT_DAA_V0 and encrypt * the v0 parameters */ blob.tag = TPM_TAG_DAA_BLOB; blob.resourceType = TPM_RT_DAA_V0; memset(blob.label, 0, sizeof(blob.label)); memset(&blob.blobIntegrity, 0, sizeof(TPM_DIGEST)); blob.additionalSize = TPM_SYM_KEY_SIZE; blob.additionalData = tpm_malloc(blob.additionalSize); if (blob.additionalData == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_get_random_bytes(blob.additionalData, blob.additionalSize); sensitive.tag = TPM_TAG_DAA_SENSITIVE; sensitive.internalSize = size; sensitive.internalData = scratch; if (encrypt_daa(blob.additionalData, blob.additionalSize, &sensitive, &blob.sensitiveData, &blob.sensitiveSize)) { tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_ENCRYPT_ERROR; } if (compute_daa_digest(&blob, &blob.blobIntegrity)) { debug("TPM_DAA_Join(): compute_daa_digest() failed."); tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } /* Set outputData to the encrypted TPM_DAA_BLOB */ *outputSize = sizeof_TPM_DAA_BLOB(blob); if ((*outputData = tpm_malloc(*outputSize)) == NULL) { tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } len = *outputSize; ptr = *outputData; if (tpm_marshal_TPM_DAA_BLOB(&ptr, &len, &blob)) { debug("TPM_DAA_Join(): tpm_marshal_TPM_DAA_BLOB() failed."); tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); tpm_free(*outputData); *outputSize = 0; memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ tpm_daa_update_digestContext(session, &sha1); /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 23: { /* Verify that DAA_session->DAA_stage == 23. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 23) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify inputSize0 == DAA_SIZE_v1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != DAA_SIZE_v1) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set u3 = inputData0 */ tpm_bn_init(u3); tpm_bn_import(u3, DAA_SIZE_v1, 1, inputData0); /* Set v1 = u3 + DAA_joinSession->DAA_join_u1 + * DAA_session->DAA_scratch */ tpm_bn_init(v1); tpm_bn_import(v1, sizeof(session->DAA_joinSession.DAA_join_u1), 1, session->DAA_joinSession.DAA_join_u1); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_add(v1, v1, tmp); tpm_bn_add(v1, u3, v1); /* Set DAA_tpmSpecific->DAA_digest_v1 = SHA-1(v1) */ tpm_bn_export(scratch, &size, 1, v1); tpm_bn_clear(u3), tpm_bn_clear(v1), tpm_bn_clear(tmp); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) scratch, size); tpm_sha1_final(&sha1, session->DAA_tpmSpecific.DAA_digest_v1.digest); /* Set outputData */ memset(&blob, 0, sizeof(blob)); /* Fill in TPM_DAA_BLOB with a type of TPM_RT_DAA_V1 and encrypt * the v1 parameters */ blob.tag = TPM_TAG_DAA_BLOB; blob.resourceType = TPM_RT_DAA_V1; memset(blob.label, 0, sizeof(blob.label)); memset(&blob.blobIntegrity, 0, sizeof(TPM_DIGEST)); blob.additionalSize = TPM_SYM_KEY_SIZE; blob.additionalData = tpm_malloc(blob.additionalSize); if (blob.additionalData == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_get_random_bytes(blob.additionalData, blob.additionalSize); sensitive.tag = TPM_TAG_DAA_SENSITIVE; sensitive.internalSize = size; sensitive.internalData = scratch; if (encrypt_daa(blob.additionalData, blob.additionalSize, &sensitive, &blob.sensitiveData, &blob.sensitiveSize)) { tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_ENCRYPT_ERROR; } if (compute_daa_digest(&blob, &blob.blobIntegrity)) { debug("TPM_DAA_Join(): compute_daa_digest() failed."); tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } /* Set outputData to the encrypted TPM_DAA_BLOB */ *outputSize = sizeof_TPM_DAA_BLOB(blob); if ((*outputData = tpm_malloc(*outputSize)) == NULL) { tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } len = *outputSize; ptr = *outputData; if (tpm_marshal_TPM_DAA_BLOB(&ptr, &len, &blob)) { debug("TPM_DAA_Join(): tpm_marshal_TPM_DAA_BLOB() failed."); tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); tpm_free(*outputData); *outputSize = 0; memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } tpm_free(blob.sensitiveData); tpm_free(blob.additionalData); /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific || * DAA_joinSession) */ tpm_daa_update_digestContext(session, &sha1); /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 24: { /* Verify that DAA_session->DAA_stage == 24. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 24) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == * SHA-1(DAA_tpmSpecific || DAA_joinSession) and return error * TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set outputData = enc(DAA_tpmSpecific) */ memset(&blob, 0, sizeof(blob)); blob.tag = TPM_TAG_DAA_BLOB; blob.resourceType = TPM_RT_DAA_TPM; memcpy(blob.label, "DAA_tpmSpecific", 15); memset(&blob.blobIntegrity, 0, sizeof(TPM_DIGEST)); blob.additionalSize = TPM_SYM_KEY_SIZE; blob.additionalData = tpm_malloc(blob.additionalSize); if (blob.additionalData == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_get_random_bytes(blob.additionalData, blob.additionalSize); sensitive.tag = TPM_TAG_DAA_SENSITIVE; sensitive.internalSize = len = sizeof(TPM_DAA_TPM); sensitive.internalData = ptr = tpm_malloc(sensitive.internalSize); if (sensitive.internalData == NULL) { tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } if (tpm_marshal_TPM_DAA_TPM(&ptr, &len, &session->DAA_tpmSpecific)) { debug("TPM_DAA_Join(): tpm_marshal_TPM_DAA_TPM() failed."); tpm_free(blob.additionalData); tpm_free(sensitive.internalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } if (encrypt_daa(blob.additionalData, blob.additionalSize, &sensitive, &blob.sensitiveData, &blob.sensitiveSize)) { tpm_free(blob.additionalData); tpm_free(sensitive.internalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_ENCRYPT_ERROR; } if (compute_daa_digest(&blob, &blob.blobIntegrity)) { debug("TPM_DAA_Join(): compute_daa_digest() failed."); tpm_free(blob.sensitiveData); tpm_free(sensitive.internalData); tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } *outputSize = sizeof_TPM_DAA_BLOB(blob); if ((*outputData = tpm_malloc(*outputSize)) == NULL) { tpm_free(blob.sensitiveData); tpm_free(sensitive.internalData); tpm_free(blob.additionalData); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } len = *outputSize; ptr = *outputData; if (tpm_marshal_TPM_DAA_BLOB(&ptr, &len, &blob)) { debug("TPM_DAA_Join(): tpm_marshal_TPM_DAA_BLOB() failed."); tpm_free(blob.sensitiveData); tpm_free(sensitive.internalData); tpm_free(blob.additionalData); tpm_free(*outputData); *outputSize = 0; memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } tpm_free(blob.sensitiveData); tpm_free(sensitive.internalData); tpm_free(blob.additionalData); /* Terminate the DAA session and all resources assoociated with the * DAA sign session handle. */ memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); /* Return TPM_SUCCESS */ return TPM_SUCCESS; } default: return TPM_DAA_STAGE; } } TPM_RESULT TPM_DAA_Sign(TPM_HANDLE handle, BYTE stage, UINT32 inputSize0, BYTE *inputData0, UINT32 inputSize1, BYTE *inputData1, TPM_AUTH *auth1, TPM_COMMAND_CODE *ordinal, UINT32 *outputSize, BYTE **outputData) { BYTE scratch[SCRATCH_SIZE]; TPM_DAA_SESSION_DATA *session = NULL; TPM_RESULT res; tpm_sha1_ctx_t sha1; BYTE *ptr, *buf; UINT32 len; TPM_DAA_BLOB blob; TPM_DAA_SENSITIVE sensitive; TPM_DIGEST digest; BYTE *DAA_generic_R0 = NULL, *DAA_generic_R1 = NULL, *DAA_generic_n = NULL, *DAA_generic_S0 = NULL, *DAA_generic_S1 = NULL, *DAA_generic_gamma = NULL; BYTE mgf1_seed[2 + sizeof(TPM_DIGEST)]; tpm_bn_t X, Y, Z, n, w1, w, gamma, q, f, E, r0, r1, r, E1, f0, s0, f1, s1, r2, s2, s12, r4, s3, tmp; BYTE selector; size_t size; TPM_KEY_DATA *aikData; TPM_KEY_HANDLE aikHandle; info("TPM_DAA_Sign()"); debug("handle = %.8x, stage = %d", handle, stage); debug("stany.data.currentDAA = %.8x", tpmData.stany.data.currentDAA); /* Initalize internal scratch pad */ memset(scratch, 0, SCRATCH_SIZE); /* Verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* Verify and initalize the session, for all stages greater than zero. */ if (stage > 0) { if ((HANDLE_TO_INDEX(handle) >= TPM_MAX_SESSIONS_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].type != TPM_ST_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].handle != handle)) { /* Probe, whether the handle from stany.data.currentDAA is valid. */ handle = tpmData.stany.data.currentDAA; if ((HANDLE_TO_INDEX(handle) >= TPM_MAX_SESSIONS_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].type != TPM_ST_DAA) || (tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)].handle != handle)) return TPM_BAD_HANDLE; } session = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)]; } /* TPM_DAA_SIGN [TPM_Part3], Section 26.2, Rev. 85 */ switch (stage) { case 0: { /* Determine that sufficient resources are available to perform a * DAA_Sign. Assign session handle for this DAA_Sign. */ handle = tpm_get_free_daa_session(); if (handle == TPM_INVALID_HANDLE) return TPM_RESOURCES; session = &tpmData.stany.data.sessionsDAA[HANDLE_TO_INDEX(handle)]; /* Verify that sizeOf(inputData0) == sizeOf(TPM_DAA_ISSUER) * and return error TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(TPM_DAA_ISSUER)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_issuerSettings = inputData0. */ /* Verify that all fields in DAA_issuerSettings are present and * return error TPM_DAA_INPUT_DATA0 if not. */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_TPM_DAA_ISSUER(&ptr, &len, &session->DAA_issuerSettings) || (len != 0) || (session->DAA_issuerSettings.tag != TPM_TAG_DAA_ISSUER)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set all fields in DAA_session = NULL */ memset(&session->DAA_session, 0, sizeof(TPM_DAA_CONTEXT)); /* Assign new handle for session */ tpmData.stany.data.currentDAA = handle; debug("TPM_DAA_Sign() -- set handle := %.8x", handle); /* Set outputData to new handle */ *outputSize = sizeof(TPM_HANDLE); if ((*outputData = tpm_malloc(*outputSize)) != NULL) { ptr = *outputData, len = *outputSize; if (tpm_marshal_TPM_HANDLE(&ptr, &len, handle)) { debug("TPM_DAA_Sign(): tpm_marshal_TPM_HANDLE() failed."); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_FAIL; } } else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Set DAA_session->DAA_stage = 1 */ session->DAA_session.DAA_stage = 1; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 1: { /* Verify that DAA_session->DAA_stage == 1. Return TPM_DAA_STAGE and * flush handle on mismatch */ if (session->DAA_session.DAA_stage != 1) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Set DAA_tpmSpecific = unwrap(inputData0) */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_TPM_DAA_BLOB(&ptr, &len, &blob) || (len != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } sensitive.internalData = scratch; if (decrypt_daa(blob.additionalData, blob.additionalSize, blob.sensitiveData, blob.sensitiveSize, &sensitive, &buf)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DECRYPT_ERROR; } if (compute_daa_digest(&blob, &digest) || memcmp(&digest, &blob.blobIntegrity, sizeof(TPM_DIGEST))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((blob.resourceType != TPM_RT_DAA_TPM) || (sensitive.tag != TPM_TAG_DAA_SENSITIVE || (sensitive.internalSize != sizeof(TPM_DAA_TPM)))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if (tpm_unmarshal_TPM_DAA_TPM(&sensitive.internalData, &sensitive.internalSize, &session->DAA_tpmSpecific)) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } tpm_free(buf); /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Set DAA_session->DAA_digestContext = SHA-1(DAA_tpmSpecific) */ tpm_daa_update_digestContext_sign(session, &sha1); /* Obtain random data from the RNG and store it as * DAA_session->DAA_contextSeed */ tpm_get_random_bytes(session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Set DAA_session->DAA_stage = 2 */ session->DAA_session.DAA_stage = 2; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 2: { /* Verify that DAA_session->DAA_stage == 2. Return TPM_DAA_STAGE and * flush handle on mismatch */ if (session->DAA_session.DAA_stage != 2) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_R0 = inputData0 */ DAA_generic_R0 = inputData0; /* Verify that SHA-1(DAA_generic_R0) == * DAA_issuerSettings->DAA_digest_R0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_R0, DAA_generic_R0, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r0 bits from MGF1("r0", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r0", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r0); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r0, 1, scratch); /* Set X = DAA_generic_R0 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_R0); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set DAA_session->DAA_scratch = (X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 3: { /* Verify that DAA_session->DAA_stage == 3. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 3) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_R1 = inputData0 */ DAA_generic_R1 = inputData0; /* Verify that SHA-1(DAA_generic_R1) == * DAA_issuerSettings->DAA_digest_R1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_R1, DAA_generic_R1, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r1 bits from MGF1("r1", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r1", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r1); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r1, 1, scratch); /* Set X = DAA_generic_R1 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_R1); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 4: { /* Verify that DAA_session->DAA_stage == 4. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 4) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_S0 = inputData0 */ DAA_generic_S0 = inputData0; /* Verify that SHA-1(DAA_generic_S0) == * DAA_issuerSettings->DAA_digest_S0 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_S0, DAA_generic_S0, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r2 bits from MGF1("r2", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r2", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r2); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r2, 1, scratch); /* Set X = DAA_generic_S0 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_S0); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, tmp); tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 5: { /* Verify that DAA_session->DAA_stage == 5. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 5) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_S1 = inputData0 */ DAA_generic_S1 = inputData0; /* Verify that SHA-1(DAA_generic_S1) == * DAA_issuerSettings->DAA_digest_S1 and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_S1, DAA_generic_S1, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_generic_n = inputData1 */ DAA_generic_n = inputData1; /* Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings->DAA_digest_n * and return error TPM_DAA_INPUT_DATA1 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_n, DAA_generic_n, inputSize1, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Obtain DAA_SIZE_r4 bits from MGF1("r4", * DAA_session->DAA_contextSeed), and label them Y */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r4", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r4); tpm_bn_init(Y); tpm_bn_import(Y, DAA_SIZE_r4, 1, scratch); /* Set X = DAA_generic_S1 */ tpm_bn_init(X); tpm_bn_import(X, inputSize0, 1, DAA_generic_S1); /* Set n = DAA_generic_n */ tpm_bn_init(n); tpm_bn_import(n, inputSize1, 1, DAA_generic_n); /* Set Z = DAA_session->DAA_scratch */ tpm_bn_init(Z); tpm_bn_import(Z, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); /* Set DAA_session->DAA_scratch = Z*(X^Y) mod n */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_init(tmp); tpm_bn_powm(tmp, X, Y, n); tpm_bn_mul(tmp, tmp, Z); tpm_bn_mod(tmp, tmp, n); tpm_bn_export(session->DAA_session.DAA_scratch, &size, 1, tmp); *outputSize = (uint32_t)size; tpm_bn_clear(X), tpm_bn_clear(Y), tpm_bn_clear(Z), tpm_bn_clear(n), tpm_bn_clear(tmp); /* Set outputData = DAA_session->DAA_scratch */ if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, session->DAA_session.DAA_scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 6: { /* Verify that DAA_session->DAA_stage == 6. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 6) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_gamma = inputData0 */ DAA_generic_gamma = inputData0; /* Verify that SHA-1(DAA_generic_gamma) == * DAA_issuerSettings->DAA_digest_gamma and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_gamma, DAA_generic_gamma, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Verify that inputSize1 == DAA_SIZE_w and return error * TPM_DAA_INPUT_DATA1 on mismatch */ if (inputSize1 != DAA_SIZE_w) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set w = inputData1 */ tpm_bn_init(w); tpm_bn_import(w, inputSize1, 1, inputData1); /* Set w1 = w^(DAA_issuerSettings->DAA_generic_q) mod * (DAA_generic_gamma) */ tpm_bn_init(gamma); tpm_bn_import(gamma, inputSize0, 1, DAA_generic_gamma); tpm_bn_init(q); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_init(w1); tpm_bn_powm(w1, w, q, gamma); /* If w1 != 1 (unity), return error TPM_DAA_WRONG_W */ if (tpm_bn_cmp_ui(w1, 1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_WRONG_W; } /* Set DAA_session->DAA_scratch = w */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, w); tpm_bn_clear(w), tpm_bn_clear(gamma), tpm_bn_clear(w1), tpm_bn_clear(q); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 7: { /* Verify that DAA_session->DAA_stage == 7. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 7) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_gamma = inputData0 */ DAA_generic_gamma = inputData0; /* Verify that SHA-1(DAA_generic_gamma) == * DAA_issuerSettings->DAA_digest_gamma and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_gamma, DAA_generic_gamma, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set f = SHA-1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0) || SHA-1(DAA_tpmSpecific->DAA_rekey * || DAA_tpmSpecific->DAA_count || 1) mod * DAA_issuerSettings->DAA_generic_q. */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Set E = ((DAA_session->DAA_scratch)^f) mod (DAA_generic_gamma).*/ tpm_bn_init(gamma); tpm_bn_import(gamma, inputSize0, 1, DAA_generic_gamma); tpm_bn_init(w); tpm_bn_import(w, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_init(E); tpm_bn_powm(E, w, f, gamma); /* Set outputData = E */ tpm_bn_export(scratch, &size, 1, E); *outputSize = (uint32_t)size; tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(gamma), tpm_bn_clear(w), tpm_bn_clear(E); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 8: { /* Verify that DAA_session->DAA_stage == 8. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 8) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_generic_gamma = inputData0 */ DAA_generic_gamma = inputData0; /* Verify that SHA-1(DAA_generic_gamma) == * DAA_issuerSettings->DAA_digest_gamma and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (tpm_daa_verify_generic(session->DAA_issuerSettings.DAA_digest_gamma, DAA_generic_gamma, inputSize0, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Obtain DAA_SIZE_r0 bits from MGF1("r0", * DAA_session->DAA_contextSeed), and label them r0 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r0", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r0); tpm_bn_init(r0); tpm_bn_import(r0, DAA_SIZE_r0, 1, scratch); /* Obtain DAA_SIZE_r1 bits from MGF1("r1", * DAA_session->DAA_contextSeed), and label them r1 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r1", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r1); tpm_bn_init(r1); tpm_bn_import(r1, DAA_SIZE_r1, 1, scratch); /* Set r = r0 + 2^DAA_power0 * r1 mod * (DAA_issuerSettings->DAA_generic_q). */ tpm_bn_init(q); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_init(r); tpm_bn_ui_pow_ui(r, 2, DAA_power0); tpm_bn_mul(r, r, r1); tpm_bn_mod(r, r, q); tpm_bn_add(r, r, r0); tpm_bn_mod(r, r, q); /* Set E1 = ((DAA_session->DAA_scratch)^r) mod (DAA_generic_gamma). */ tpm_bn_init(gamma); tpm_bn_import(gamma, inputSize0, 1, DAA_generic_gamma); tpm_bn_init(w); tpm_bn_import(w, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_init(E1); tpm_bn_powm(E1, w, r, gamma); /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Set outputData = E1 */ tpm_bn_export(scratch, &size, 1, E1); *outputSize = (uint32_t)size; tpm_bn_clear(r0), tpm_bn_clear(r1), tpm_bn_clear(q), tpm_bn_clear(r); tpm_bn_clear(gamma), tpm_bn_clear(w), tpm_bn_clear(E1); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 9: { BYTE *NT = NULL; /* Verify that DAA_session->DAA_stage == 9. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 9) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Verify that inputSize0 == sizeOf(TPM_DIGEST) and return error * TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(TPM_DIGEST)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Set DAA_session->DAA_digest = inputData0 */ memcpy(&session->DAA_session.DAA_digest, inputData0, inputSize0); /* Obtain DAA_SIZE_NT bytes from the RNG and label them NT */ if ((NT = tpm_malloc(DAA_SIZE_NT)) == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_get_random_bytes(NT, DAA_SIZE_NT); /* Set DAA_session->DAA_digest to the SHA-1(DAA_session->DAA_digest || * NT)*/ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_session.DAA_digest, sizeof(session->DAA_session.DAA_digest)); tpm_sha1_update(&sha1, NT, DAA_SIZE_NT); tpm_sha1_final(&sha1, session->DAA_session.DAA_digest.digest); /* Set outputData = NT */ *outputSize = DAA_SIZE_NT; if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, NT, *outputSize); else { tpm_free(NT); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } tpm_free(NT); /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 10: { /* Verify that DAA_session->DAA_stage == 10. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 10) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set selector = inputData0, verify that selector == 0 or 1, and * return error TPM_DAA_INPUT_DATA0 on mismatch */ if (inputSize0 != sizeof(selector)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } memcpy(&selector, inputData0, sizeof(selector)); if ((selector != '\x00') && (selector != '\x01')) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* If selector == 1, verify that inputSize1 == sizeOf(TPM_DIGEST), and */ if (selector == '\x01') { debug("DAA_Sign(): selector == 1"); if (inputSize1 != sizeof(TPM_DIGEST)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set DAA_session->DAA_digest to SHA-1(DAA_session->DAA_digest || * 1 || inputData1) */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_session.DAA_digest, sizeof(session->DAA_session.DAA_digest)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_update(&sha1, inputData1, inputSize1); tpm_sha1_final(&sha1, (BYTE*) &session->DAA_session.DAA_digest); } /* If selector == 0, verify that inputData1 is a handle to a TPM * identity key (AIK), and */ if (selector == '\x00') { debug("DAA_Sign(): selector == 0"); if (tpm_unmarshal_TPM_KEY_HANDLE(&inputData1, &inputSize1, &aikHandle) || (inputSize1 != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } debug("DAA_Sign(): aikHandle == %.8x", aikHandle); aikData = tpm_get_key(aikHandle); if (aikData == NULL) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } if (aikData->keyUsage != TPM_KEY_IDENTITY) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA1; } /* Set DAA_session->DAA_digest to SHA-1(DAA_session->DAA_digest || * 0 || n2) where n2 is the modulus of the AIK */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_session.DAA_digest, sizeof(session->DAA_session.DAA_digest)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_rsa_export_modulus(&aikData->key, scratch, &size); tpm_sha1_update(&sha1, scratch, size); tpm_sha1_final(&sha1, (BYTE*) &session->DAA_session.DAA_digest); } /* Set outputData = DAA_session->DAA_digest */ *outputSize = sizeof(session->DAA_session.DAA_digest); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, &session->DAA_session.DAA_digest, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 11: { /* Verify that DAA_session->DAA_stage == 11. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 11) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r0 bits from MGF1("r0", * DAA_session->DAA_contextSeed), and label them r0 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r0", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r0); tpm_bn_init(r0); tpm_bn_import(r0, DAA_SIZE_r0, 1, scratch); /* Set f = SHA1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0 ) || * SHA1(DAA_tpmSpecific->DAA_rekey || DAA_tpmSpecific->DAA_count || * 1 ) mod DAA_issuerSettings->DAA_generic_q */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 * bits of f) */ tpm_bn_init(f0); tpm_bn_init(tmp); tpm_bn_ui_pow_ui(tmp, 2, DAA_power0); tpm_bn_mod(f0, f, tmp); /* Set s0 = r0 + (DAA_session->DAA_digest) * (f0) */ tpm_bn_init(s0); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s0, tmp, f0); tpm_bn_add(s0, r0, s0); /* Set outputData = s0 */ tpm_bn_export(scratch, &size, 1, s0); *outputSize = (uint32_t)size; tpm_bn_clear(r0), tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(f0); tpm_bn_clear(s0), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 12: { /* Verify that DAA_session->DAA_stage == 12. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 12) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Obtain DAA_SIZE_r1 bits from MGF1("r1", * DAA_session->DAA_contextSeed), and label them r1 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r1", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r1); tpm_bn_init(r1); tpm_bn_import(r1, DAA_SIZE_r1, 1, scratch); /* Set f = SHA1(DAA_tpmSpecific->DAA_rekey || * DAA_tpmSpecific->DAA_count || 0 ) || * SHA1(DAA_tpmSpecific->DAA_rekey || DAA_tpmSpecific->DAA_count || * 1 ) mod DAA_issuerSettings->DAA_generic_q */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_00, 1); tpm_sha1_final(&sha1, scratch); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_rekey, sizeof(session->DAA_tpmSpecific.DAA_rekey)); tpm_sha1_update(&sha1, (BYTE*) &session->DAA_tpmSpecific.DAA_count, sizeof(session->DAA_tpmSpecific.DAA_count)); tpm_sha1_update(&sha1, DAA_LABEL_01, 1); tpm_sha1_final(&sha1, scratch + SHA1_DIGEST_LENGTH); tpm_bn_init(f), tpm_bn_init(q); tpm_bn_import(f, 2 * SHA1_DIGEST_LENGTH, 1, scratch); tpm_bn_import(q, sizeof(session->DAA_issuerSettings.DAA_generic_q), 1, session->DAA_issuerSettings.DAA_generic_q); tpm_bn_mod(f, f, q); /* Shift f right by DAA_power0 bits (discard the lowest DAA_power0 * bits) and label the result f1 */ tpm_bn_init(f1); tpm_bn_fdiv_q_2exp(f1, f, DAA_power0); /* Set s1 = r1 + (DAA_session->DAA_digest) * (f1) */ tpm_bn_init(s1); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s1, tmp, f1); tpm_bn_add(s1, r1, s1); /* Set outputData = s1 */ tpm_bn_export(scratch, &size, 1, s1); *outputSize = (uint32_t)size; tpm_bn_clear(r1), tpm_bn_clear(f), tpm_bn_clear(q), tpm_bn_clear(f1); tpm_bn_clear(s1), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 13: { BYTE *DAA_private_v0 = NULL; /* Verify that DAA_session->DAA_stage == 13. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 13) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_private_v0 = unwrap(inputData0) */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_TPM_DAA_BLOB(&ptr, &len, &blob) || (len != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } sensitive.internalData = scratch; if (decrypt_daa(blob.additionalData, blob.additionalSize, blob.sensitiveData, blob.sensitiveSize, &sensitive, &buf)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DECRYPT_ERROR; } if (compute_daa_digest(&blob, &digest) || memcmp(&digest, &blob.blobIntegrity, sizeof(TPM_DIGEST))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((blob.resourceType != TPM_RT_DAA_V0) || (sensitive.tag != TPM_TAG_DAA_SENSITIVE || (sensitive.internalSize == 0) || (sensitive.internalSize > DAA_SIZE_v0))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((DAA_private_v0 = tpm_malloc(DAA_SIZE_v0)) == NULL) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } memcpy(DAA_private_v0, sensitive.internalData, sensitive.internalSize); tpm_free(buf); /* Verify that SHA-1(DAA_private_v0) == DAA_tpmSpecific->DAA_digest_v0 * and return error TPM_DAA_INPUT_DATA0 on mismatch */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, DAA_private_v0, sensitive.internalSize); tpm_sha1_final(&sha1, (BYTE*) &digest); if (memcmp(&digest, &session->DAA_tpmSpecific.DAA_digest_v0, sizeof(TPM_DIGEST))) { tpm_free(DAA_private_v0); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Obtain DAA_SIZE_r2 bits from MGF1("r2", * DAA_session->DAA_contextSeed), and label them r2 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r2", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r2); tpm_bn_init(r2); tpm_bn_import(r2, DAA_SIZE_r2, 1, scratch); /* Set s2 = r2 + (DAA_session->DAA_digest) * * (DAA_private_v0) mod 2^DAA_power1 * (Erase all but the lowest DAA_power1 bits of s2) */ tpm_bn_init(s2); tpm_bn_import(s2, sensitive.internalSize, 1, DAA_private_v0); tpm_free(DAA_private_v0); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s2, tmp, s2); tpm_bn_add(s2, r2, s2); tpm_bn_ui_pow_ui(tmp, 2, DAA_power1); tpm_bn_mod(s2, s2, tmp); /* Set DAA_session->DAA_scratch = s2 */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, s2); /* Set outputData = s2 */ tpm_bn_export(scratch, &size, 1, s2); *outputSize = (uint32_t)size; tpm_bn_clear(r2), tpm_bn_clear(s2), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 14: { BYTE *DAA_private_v0 = NULL; /* Verify that DAA_session->DAA_stage == 14. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 14) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_private_v0 = unwrap(inputData0) */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_TPM_DAA_BLOB(&ptr, &len, &blob) || (len != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } sensitive.internalData = scratch; if (decrypt_daa(blob.additionalData, blob.additionalSize, blob.sensitiveData, blob.sensitiveSize, &sensitive, &buf)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DECRYPT_ERROR; } if (compute_daa_digest(&blob, &digest) || memcmp(&digest, &blob.blobIntegrity, sizeof(TPM_DIGEST))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((blob.resourceType != TPM_RT_DAA_V0) || (sensitive.tag != TPM_TAG_DAA_SENSITIVE || (sensitive.internalSize == 0) || (sensitive.internalSize > DAA_SIZE_v0))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((DAA_private_v0 = tpm_malloc(DAA_SIZE_v0)) == NULL) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } memcpy(DAA_private_v0, sensitive.internalData, sensitive.internalSize); tpm_free(buf); /* Verify that SHA-1(DAA_private_v0) == DAA_tpmSpecific->DAA_digest_v0 * and return error TPM_DAA_INPUT_DATA0 on mismatch */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, DAA_private_v0, sensitive.internalSize); tpm_sha1_final(&sha1, (BYTE*) &digest); if (memcmp(&digest, &session->DAA_tpmSpecific.DAA_digest_v0, sizeof(TPM_DIGEST))) { tpm_free(DAA_private_v0); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Obtain DAA_SIZE_r2 bits from MGF1("r2", * DAA_session->DAA_contextSeed), and label them r2 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r2", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r2); tpm_bn_init(r2); tpm_bn_import(r2, DAA_SIZE_r2, 1, scratch); /* Set s12 = r2 + (DAA_session->DAA_digest) * (DAA_private_v0). */ tpm_bn_init(s12); tpm_bn_import(s12, sensitive.internalSize, 1, DAA_private_v0); tpm_free(DAA_private_v0); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s12, tmp, s12); tpm_bn_add(s12, r2, s12); /* Shift s12 right by DAA_power1 bits (erase the lowest DAA_power1 * bits). */ tpm_bn_fdiv_q_2exp(s12, s12, DAA_power1); /* Set DAA_session->DAA_scratch = s12 */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); tpm_bn_export(session->DAA_session.DAA_scratch, NULL, -1, s12); tpm_bn_clear(r2), tpm_bn_clear(s12), tpm_bn_clear(tmp); /* Set outputData = NULL */ *outputSize = 0, *outputData = NULL; /* Increment DAA_session->DAA_stage by 1 */ session->DAA_session.DAA_stage++; /* Return TPM_SUCCESS */ return TPM_SUCCESS; } case 15: { BYTE *DAA_private_v1 = NULL; /* Verify that DAA_session->DAA_stage == 15. Return TPM_DAA_STAGE * and flush handle on mismatch */ if (session->DAA_session.DAA_stage != 15) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_STAGE; } /* Verify that DAA_tpmSpecific->DAA_digestIssuer == * SHA-1(DAA_issuerSettings) and return error TPM_DAA_ISSUER_SETTINGS * on mismatch */ if (tpm_daa_verify_digestIssuer(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_ISSUER_SETTINGS; } /* Verify that DAA_session->DAA_digestContext == SHA-1(DAA_tpmSpecific) * and return error TPM_DAA_TPM_SETTINGS on mismatch */ if (tpm_daa_verify_digestContext_sign(session, &sha1)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_TPM_SETTINGS; } /* Set DAA_private_v1 = unwrap(inputData0) */ ptr = inputData0, len = inputSize0; if (tpm_unmarshal_TPM_DAA_BLOB(&ptr, &len, &blob) || (len != 0)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } sensitive.internalData = scratch; if (decrypt_daa(blob.additionalData, blob.additionalSize, blob.sensitiveData, blob.sensitiveSize, &sensitive, &buf)) { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DECRYPT_ERROR; } if (compute_daa_digest(&blob, &digest) || memcmp(&digest, &blob.blobIntegrity, sizeof(TPM_DIGEST))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((blob.resourceType != TPM_RT_DAA_V1) || (sensitive.tag != TPM_TAG_DAA_SENSITIVE || (sensitive.internalSize == 0) || (sensitive.internalSize > DAA_SIZE_v1))) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } if ((DAA_private_v1 = tpm_malloc(DAA_SIZE_v1)) == NULL) { tpm_free(buf); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } memcpy(DAA_private_v1, sensitive.internalData, sensitive.internalSize); tpm_free(buf); /* Verify that SHA-1(DAA_private_v1) == DAA_tpmSpecific->DAA_digest_v1 * and return error TPM_DAA_INPUT_DATA0 on mismatch */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, DAA_private_v1, sensitive.internalSize); tpm_sha1_final(&sha1, (BYTE*) &digest); if (memcmp(&digest, &session->DAA_tpmSpecific.DAA_digest_v1, sizeof(TPM_DIGEST))) { tpm_free(DAA_private_v1); memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_DAA_INPUT_DATA0; } /* Obtain DAA_SIZE_r4 bits from MGF1("r4", * DAA_session->DAA_contextSeed), and label them r4 */ memset(scratch, 0, sizeof(scratch)); memcpy(mgf1_seed, "r4", 2); memcpy(mgf1_seed + 2, session->DAA_session.DAA_contextSeed.nonce, sizeof(TPM_NONCE)); tpm_rsa_mask_generation(mgf1_seed, sizeof(mgf1_seed), scratch, DAA_SIZE_r4); tpm_bn_init(r4); tpm_bn_import(r4, DAA_SIZE_r4, 1, scratch); /* Set s3 = r4 + (DAA_session->DAA_digest) * (DAA_private_v1) + * (DAA_session->DAA_scratch). */ tpm_bn_init(s3); tpm_bn_import(s3, sensitive.internalSize, 1, DAA_private_v1); tpm_free(DAA_private_v1); tpm_bn_init(tmp); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_digest.digest), 1, session->DAA_session.DAA_digest.digest); tpm_bn_mul(s3, tmp, s3); tpm_bn_add(s3, r4, s3); tpm_bn_import(tmp, sizeof(session->DAA_session.DAA_scratch), -1, session->DAA_session.DAA_scratch); tpm_bn_add(s3, s3, tmp); /* Set DAA_session->DAA_scratch = NULL */ memset(session->DAA_session.DAA_scratch, 0, sizeof(session->DAA_session.DAA_scratch)); /* Set outputData = s3 */ tpm_bn_export(scratch, &size, 1, s3); *outputSize = (uint32_t)size; tpm_bn_clear(r4), tpm_bn_clear(s3), tpm_bn_clear(tmp); if ((*outputData = tpm_malloc(*outputSize)) != NULL) memcpy(*outputData, scratch, *outputSize); else { memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); return TPM_NOSPACE; } /* Terminate the DAA session and all resources assoociated with the * DAA sign session handle. */ memset(session, 0, sizeof(TPM_DAA_SESSION_DATA)); /* Return TPM_SUCCESS */ return TPM_SUCCESS; } default: return TPM_DAA_STAGE; } } ================================================ FILE: tpm/tpm_data.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_data.c 372 2010-02-15 12:52:00Z mast $ */ #include "tpm_emulator.h" #include "tpm_structures.h" #include "tpm_marshalling.h" #include "tpm_commands.h" #include "tpm_data.h" TPM_DATA tpmData; UINT32 tpmConf; #ifdef MTM_EMULATOR #include "mtm/mtm_data.h" #include "mtm/mtm_marshalling.h" #endif static TPM_VERSION tpm_version = { 1, 2, VERSION_MAJOR, VERSION_MINOR }; BOOL tpm_get_physical_presence(void) { return (tpmData.stclear.flags.physicalPresence || TRUE); } static inline void init_pcr_attr(int pcr, BOOL reset, BYTE rl, BYTE el) { tpmData.permanent.data.pcrAttrib[pcr].pcrReset = reset; tpmData.permanent.data.pcrAttrib[pcr].pcrResetLocal = rl; tpmData.permanent.data.pcrAttrib[pcr].pcrExtendLocal = el; } static void init_nv_storage(void) { TPM_NV_DATA_SENSITIVE *nv; memset(tpmData.permanent.data.nvData, 0xff, TPM_MAX_NV_SIZE); /* init TPM_NV_INDEX_DIR */ nv = &tpmData.permanent.data.nvStorage[0]; memset(nv, 0, sizeof(TPM_NV_DATA_SENSITIVE)); nv->tag = TPM_TAG_NV_DATA_SENSITIVE; nv->pubInfo.tag = TPM_TAG_NV_DATA_PUBLIC; nv->pubInfo.nvIndex = TPM_NV_INDEX_DIR; nv->pubInfo.pcrInfoRead.localityAtRelease = 0x1f; nv->pubInfo.pcrInfoWrite.localityAtRelease = 0x1f; nv->pubInfo.permission.tag = TPM_TAG_NV_ATTRIBUTES; nv->pubInfo.permission.attributes = TPM_NV_PER_OWNERWRITE | TPM_NV_PER_WRITEALL; nv->pubInfo.dataSize = 20; nv->dataIndex = 0; nv->valid = TRUE; /* set NV data size */ tpmData.permanent.data.nvDataSize = 20; } static void init_timeouts(void) { /* for the timeouts we use the PC platform defaults */ tpmData.permanent.data.tis_timeouts[0] = 750; tpmData.permanent.data.tis_timeouts[1] = 2000; tpmData.permanent.data.tis_timeouts[2] = 750; tpmData.permanent.data.tis_timeouts[3] = 750; tpmData.permanent.data.cmd_durations[0] = 1; tpmData.permanent.data.cmd_durations[1] = 10; tpmData.permanent.data.cmd_durations[2] = 1000; } void tpm_init_data(void) { /* endorsement key */ uint8_t ek_n[] = "\xa8\xdb\xa9\x42\xa8\xf3\xb8\x06\x85\x90\x76\x93\xad\xf7" "\x74\xec\x3f\xd3\x3d\x9d\xe8\x2e\xff\x15\xed\x0e\xce\x5f\x93" "\x92\xeb\xd1\x96\x2b\x72\x18\x81\x79\x12\x9d\x9c\x40\xd7\x1a" "\x21\xda\x5f\x56\xe0\xc9\x48\x31\xdd\x96\xdc\xbb\x45\xc6\x8e" "\xad\x58\x23\xcb\xbe\xbb\x13\x2d\x6b\x86\xc5\x57\xf5\xdd\x48" "\xc1\x3d\xcd\x4d\xda\x81\xc4\x43\x17\xaa\x05\x40\x33\x62\x0a" "\x59\xdb\x28\xcd\xb5\x08\x31\xbb\x06\xf5\xf7\x71\xae\x21\xa8" "\xf2\x2f\x0e\x17\x80\x5d\x9c\xdf\xaa\xe9\x89\x09\x54\x65\x2b" "\x46\xfb\x9d\xb2\x00\x70\x63\x0d\x9a\x6d\x3d\x5e\x11\x78\x65" "\x90\xe6\x26\xee\x77\xbe\x08\xff\x07\x60\x5a\xcc\xf1\x0a\xbd" "\x44\x92\x6b\xca\xb6\xce\x66\xf9\x93\x40\xae\xf3\x3e\x53\x02" "\x3c\xa6\x81\xb3\xbe\xad\x6e\x6c\xa6\xf0\xeb\xdf\xe9\xa2\x83" "\x36\x0e\x52\x0d\x64\x17\xd9\xff\xa1\x74\x7c\x2b\xbc\x6a\xcc" "\xe5\x4e\xb4\x52\xd9\xec\x43\xbd\x26\x6a\x2b\x19\x19\x6e\x97" "\xb8\x1d\x9f\x7b\xe7\x32\x2d\xdd\x7c\x51\xc8\xe4\xf3\x02\xd4" "\x7c\x90\x44\xa0\x33\x72\x81\x75\xa9\x16\x27\x5c\x00\x1d\x07" "\x81\xd4\xf7\xac\xcb\xfe\xd6\x60\x03\x6f\x7a\xcc\x00\xd1\xc4" "\x85\x37"; uint8_t ek_e[] = "\x01\x00\x01"; uint8_t ek_p[] = "\xd7\xea\x61\x15\x8b\xa3\x71\xdf\xa8\x74\x77\xca\x88\x95" "\xd0\x76\x17\x43\x2c\xf6\x23\x27\x44\xb9\x0e\x18\x35\x7e\xe4" "\xc3\xcb\x13\x6e\xfc\x38\x02\x1e\x77\x26\x40\x9d\x17\xb2\x39" "\x9c\x7f\x5f\x98\xe6\xf2\x55\x0c\x12\x05\x4c\xb3\x51\xae\x29" "\xe7\xcd\xce\x41\x0b\x28\x4d\x97\x13\x4b\x60\xc8\xd8\x70\x81" "\xf9\x1c\x12\x44\xdf\x53\x0a\x87\x9d\x33\x92\x4a\x34\x69\xf0" "\x70\x5e\x1b\x5d\x65\xc7\x84\x90\xa2\x62\xdf\x83\x14\x10\x69" "\xe2\xa7\x18\x43\xd7\x1f\x60\xc9\x03\x8f\xd6\xa4\xce\xb2\x9d" "\x40\x37\x70\x17\x4c\xe3\x69\xd4\x59"; uint8_t ek_q[] = "\xc8\x34\xd2\xd0\x7c\xfa\xdc\x68\xe2\x72\xd7\x92\xe2\x50" "\x93\xfc\xbb\x72\x55\x4d\x6b\x7a\x0c\x0b\xcf\x87\x66\x1f\x81" "\x71\xf3\x50\xcb\xaa\xe6\x43\x7e\xbe\x11\xc4\xec\x00\x53\xf4" "\x78\x13\x2b\x59\x26\x4a\x9f\x91\x61\x8f\xa7\x07\x64\x11\x5a" "\xf4\xaf\x9c\x9b\x5a\x5d\x69\x20\x17\x55\x74\xba\xd8\xe4\x59" "\x39\x1a\x0a\x7b\x4a\x30\xf0\xc8\x7f\xd9\xaf\x72\xc5\xb6\x71" "\xd1\xc0\x8b\x5b\xa2\x2e\xa7\x15\xca\x50\x75\x10\x48\x9c\x2b" "\x18\xb9\x67\x8f\x5d\x64\xc3\x28\x9f\x2f\x16\x2f\x08\xda\x47" "\xec\x86\x43\x0c\x80\x99\x07\x34\x0f"; int i; info("initializing TPM data to default values"); /* reset all data to NULL, FALSE or 0 */ memset(&tpmData, 0, sizeof(tpmData)); tpmData.permanent.data.tag = TPM_TAG_PERMANENT_DATA; /* set permanent flags */ tpmData.permanent.flags.tag = TPM_TAG_PERMANENT_FLAGS; tpmData.permanent.flags.disable = FALSE; tpmData.permanent.flags.deactivated = FALSE; tpmData.permanent.flags.ownership = TRUE; tpmData.permanent.flags.readPubek = TRUE; tpmData.permanent.flags.allowMaintenance = TRUE; tpmData.permanent.flags.enableRevokeEK = TRUE; tpmData.permanent.flags.readSRKPub = TRUE; tpmData.permanent.flags.nvLocked = TRUE; /* set TPM vision */ memcpy(&tpmData.permanent.data.version, &tpm_version, sizeof(TPM_VERSION)); /* seed PRNG */ tpm_get_extern_random_bytes(&tpmData.permanent.data.rngState, sizeof(tpmData.permanent.data.rngState)); /* setup PCR attributes */ for (i = 0; i < TPM_NUM_PCR && i < 16; i++) { init_pcr_attr(i, FALSE, 0x00, 0x1f); } if (TPM_NUM_PCR >= 24) { init_pcr_attr(16, TRUE, 0x1f, 0x1f); init_pcr_attr(17, TRUE, 0x10, 0x1c); init_pcr_attr(18, TRUE, 0x10, 0x1c); init_pcr_attr(19, TRUE, 0x10, 0x0c); init_pcr_attr(20, TRUE, 0x14, 0x0e); init_pcr_attr(21, TRUE, 0x04, 0x04); init_pcr_attr(22, TRUE, 0x04, 0x04); init_pcr_attr(23, TRUE, 0x1f, 0x1f); } #if TPM_NUM_PCR > 24 for (i = 24; i < TPM_NUM_PCR; i++) { init_pcr_attr(i, TRUE, 0x00, 0x00); } #endif if (tpmConf & TPM_CONF_GENERATE_EK) { /* generate a new endorsement key */ tpm_rsa_generate_key(&tpmData.permanent.data.endorsementKey, 2048); } else { /* setup endorsement key */ tpm_rsa_import_key(&tpmData.permanent.data.endorsementKey, RSA_MSB_FIRST, ek_n, 256, ek_e, 3, ek_p, ek_q); } if (tpmConf & TPM_CONF_GENERATE_SEED_DAA) { /* generate the DAA seed */ tpm_get_random_bytes(tpmData.permanent.data.tpmDAASeed.nonce, sizeof(tpmData.permanent.data.tpmDAASeed.nonce)); } else { /* setup DAA seed */ memcpy(tpmData.permanent.data.tpmDAASeed.nonce, "\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x77", sizeof(TPM_NONCE)); } memcpy(tpmData.permanent.data.ekReset.nonce, "\xde\xad\xbe\xef", 4); /* initialize predefined non-volatile storage */ init_nv_storage(); /* set the timeout and duration values */ init_timeouts(); #ifdef MTM_EMULATOR mtm_init_data(); #endif } void tpm_release_data(void) { free_TPM_DATA(tpmData); #ifdef MTM_EMULATOR free_MTM_DATA(mtmData); #endif } 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; } int tpm_erase_permanent_data(void) { uint8_t d[1]; int res = tpm_write_to_storage(d, 0); return res; } ================================================ FILE: tpm/tpm_data.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_data.h 368 2010-02-15 09:26:37Z mast $ */ #ifndef _TPM_DATA_H_ #define _TPM_DATA_H_ #include "tpm_structures.h" extern TPM_DATA tpmData; extern UINT32 tpmConf; BOOL tpm_get_physical_presence(void); void tpm_init_data(void); void tpm_release_data(void); int tpm_store_permanent_data(void); int tpm_restore_permanent_data(void); int tpm_erase_permanent_data(void); #endif /* _TPM_DATA_H_ */ ================================================ FILE: tpm/tpm_delegation.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_delegation.c 367 2010-02-13 15:52:18Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_marshalling.h" #include "tpm_data.h" #include "tpm_handles.h" #include "crypto/hmac.h" #include "crypto/rc4.h" /* * Delegation Commands ([TPM_Part3], Section 19) */ TPM_FAMILY_TABLE_ENTRY *tpm_get_family_row(TPM_FAMILY_ID id) { UINT32 i; for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { if (tpmData.permanent.data.familyTable.famRow[i].valid && tpmData.permanent.data.familyTable.famRow[i].familyID == id) return &tpmData.permanent.data.familyTable.famRow[i]; } return NULL; } TPM_DELEGATE_TABLE_ROW *tpm_get_delegate_row(UINT32 row) { if (row < TPM_NUM_DELEGATE_TABLE_ENTRY && tpmData.permanent.data.delegateTable.delRow[row].valid) return &tpmData.permanent.data.delegateTable.delRow[row]; return NULL; } void tpm_compute_owner_blob_digest(TPM_DELEGATE_OWNER_BLOB *blob, TPM_DIGEST *digest) { tpm_hmac_ctx_t ctx; BYTE buf[sizeof_TPM_DELEGATE_OWNER_BLOB((*blob))]; BYTE *ptr = buf; UINT32 length = sizeof(buf); tpm_marshal_TPM_DELEGATE_OWNER_BLOB(&ptr, &length, blob); memset(&buf[2 + sizeof_TPM_DELEGATE_PUBLIC(blob->pub)], 0, 20); tpm_hmac_init(&ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(tpmData.permanent.data.tpmProof.nonce)); tpm_hmac_update(&ctx, buf, sizeof(buf) - length); tpm_hmac_final(&ctx, digest->digest); } void tpm_compute_key_blob_digest(TPM_DELEGATE_KEY_BLOB *blob, TPM_DIGEST *digest) { tpm_hmac_ctx_t ctx; BYTE buf[sizeof_TPM_DELEGATE_KEY_BLOB((*blob))]; BYTE *ptr = buf; UINT32 length = sizeof(buf); tpm_marshal_TPM_DELEGATE_KEY_BLOB(&ptr, &length, blob); memset(&buf[2 + sizeof_TPM_DELEGATE_PUBLIC(blob->pub)], 0, 20); tpm_hmac_init(&ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(tpmData.permanent.data.tpmProof.nonce)); tpm_hmac_update(&ctx, buf, sizeof(buf) - length); tpm_hmac_final(&ctx, digest->digest); } int tpm_encrypt_sensitive(BYTE *iv, UINT32 iv_size, TPM_DELEGATE_SENSITIVE *sensitive, 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_DELEGATE_SENSITIVE((*sensitive)); *enc = ptr = tpm_malloc(len); if (*enc == NULL) return -1; if (tpm_marshal_TPM_DELEGATE_SENSITIVE(&ptr, &len, sensitive)) { tpm_free(*enc); return -1; } /* encrypt context */ memcpy(key, tpmData.permanent.data.delegateKey, 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; } int tpm_decrypt_sensitive(BYTE *iv, UINT32 iv_size, BYTE *enc, UINT32 enc_size, TPM_DELEGATE_SENSITIVE *sensitive, 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.delegateKey, 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_DELEGATE_SENSITIVE(&ptr, &len, sensitive)) { tpm_free(*buf); return -1; } return 0; } static TPM_FAMILY_TABLE_ENTRY *tpm_get_free_family_row(void) { UINT32 i; for(i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { if(!tpmData.permanent.data.familyTable.famRow[i].valid) { tpmData.permanent.data.familyTable.famRow[i].valid = TRUE; return &tpmData.permanent.data.familyTable.famRow[i]; } } return NULL; } TPM_RESULT TPM_Delegate_Manage(TPM_FAMILY_ID familyID, TPM_FAMILY_OPERATION opFlag, UINT32 opDataSize, BYTE *opData, TPM_AUTH *auth1, UINT32 *retDataSize, BYTE **retData) { TPM_RESULT res; TPM_SESSION_DATA *session; TPM_FAMILY_TABLE_ENTRY *fr; UINT32 i; info("[TPM_Delegate_Manage]"); /* if no new family row is to be created, get the existing one */ if (opFlag != TPM_FAMILY_CREATE) { fr = tpm_get_family_row(familyID); if (fr == NULL) return TPM_BADINDEX; } else { fr = NULL; } /* verify authorization */ session = tpm_get_auth(auth1->authHandle); if (session == NULL) return TPM_AUTHFAIL; if (auth1->authHandle != TPM_INVALID_AUTHHANDLE) { res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (session->type == TPM_ST_DSAP) { if (session->familyID != familyID) return TPM_DELEGATE_FAMILY; auth1->continueAuthSession = FALSE; } } else { if (tpmData.permanent.flags.owned) return TPM_AUTHFAIL; /* check delegate admin lock */ if (fr != NULL && (fr->flags & TPM_DELEGATE_ADMIN_LOCK)) { debug("delegate admin lock is set"); return TPM_DELEGATE_LOCK; } /* verify maximal number of writes without an owner */ if (tpmData.permanent.data.noOwnerNVWrite >= TPM_MAX_NV_WRITE_NOOWNER) return TPM_MAXNVWRITES; tpmData.permanent.data.noOwnerNVWrite++; } /* invalidate all but this auth session */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { TPM_SESSION_DATA *s = &tpmData.stany.data.sessions[i]; if (s->type != TPM_ST_TRANSPORT && s != session) memset(s, 0, sizeof(*s)); } tpmData.stclear.data.ownerReference = TPM_KH_OWNER; /* perform requested operation */ if (opFlag == TPM_FAMILY_CREATE) { BYTE *ptr; UINT32 length; debug("ofFlag = TPM_FAMILY_CREATE"); if (opDataSize != 1) return TPM_BAD_PARAM_SIZE; /* get a free family row */ fr = tpm_get_free_family_row(); if (fr == NULL) return TPM_NOSPACE; /* initialize the new row */ fr->tag = TPM_TAG_FAMILY_TABLE_ENTRY; fr->familyLabel.label = *opData; tpmData.permanent.data.lastFamilyID++; fr->familyID = tpmData.permanent.data.lastFamilyID; fr->verificationCount = 1; fr->flags = 0; /* return the familyID */ length = *retDataSize = 4; ptr = *retData = tpm_malloc(*retDataSize); if (*retData == NULL) { debug("tpm_malloc() failed."); fr->valid = FALSE; return TPM_FAIL; } if (tpm_marshal_UINT32(&ptr, &length, fr->familyID) != 0) { debug("tpm_marshal_UINT32() failed."); tpm_free(*retData); fr->valid = FALSE; return TPM_FAIL; } } else if (opFlag == TPM_FAMILY_ADMIN) { debug("opFlag = TPM_FAMILY_ADMIN"); if (opDataSize != 1) return TPM_BAD_PARAM_SIZE; if (*opData)fr->flags |= TPM_DELEGATE_ADMIN_LOCK; else fr->flags &= ~TPM_DELEGATE_ADMIN_LOCK; *retDataSize = 0; } else if (opFlag == TPM_FAMILY_ENABLE) { debug("opFlag = TPM_FAMFLAG_ENABLED"); if (opDataSize != 1) return TPM_BAD_PARAM_SIZE; if (*opData)fr->flags |= TPM_FAMFLAG_ENABLED; else fr->flags &= ~TPM_FAMFLAG_ENABLED; *retDataSize = 0; return TPM_SUCCESS; } else if (opFlag == TPM_FAMILY_INVALIDATE) { debug("opFlag = TPM_FAMILY_INVALIDATE"); /* invalidate all family data */ memset(fr, 0, sizeof(*fr)); fr->valid = FALSE; *retDataSize = 0; } else { debug("unknown opFlag value: %d", opFlag); return TPM_BAD_PARAMETER; } return TPM_SUCCESS; } TPM_RESULT TPM_Delegate_CreateKeyDelegation(TPM_KEY_HANDLE keyHandle, TPM_DELEGATE_PUBLIC *publicInfo, TPM_ENCAUTH *delAuth, TPM_AUTH *auth1, TPM_DELEGATE_KEY_BLOB *blob) { TPM_RESULT res; TPM_SESSION_DATA *session; TPM_FAMILY_TABLE_ENTRY *fr; TPM_SECRET secret; TPM_KEY_DATA *key; TPM_PUBKEY pubKey; TPM_DELEGATE_SENSITIVE sensitive; info("TPM_Delegate_CreateKeyDelegation()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ session = tpm_get_auth(auth1->authHandle); if (session == NULL) return TPM_FAIL; if (session->type != TPM_ST_OSAP && session->type != TPM_ST_DSAP) { debug("session is neither of type OSAP nor DSAP"); return TPM_INVALID_AUTHHANDLE; } res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; auth1->continueAuthSession = FALSE; /* get specified family entry */ fr = tpm_get_family_row(publicInfo->familyID); if (fr == NULL) return TPM_BADINDEX; /* check delegation type */ if (publicInfo->permissions.delegateType != TPM_DEL_KEY_BITS) { debug("invalid delegation type: %d", publicInfo->permissions.delegateType); return TPM_BAD_PARAMETER; } blob->tag = TPM_TAG_DELEGATE_KEY_BLOB; /* verify permissions if the access was delegated */ if (session->type == TPM_ST_DSAP) { if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (session->familyID != publicInfo->familyID) return TPM_DELEGATE_FAMILY; if (((session->permissions.per1 | publicInfo->permissions.per1) != session->permissions.per1) || ((session->permissions.per2 | publicInfo->permissions.per2) != session->permissions.per2)) return TPM_AUTHFAIL; } /* decrypt delegation secret */ tpm_decrypt_auth_secret(*delAuth, session->sharedSecret, &session->lastNonceEven, secret); /* compute key digest */ if (tpm_extract_pubkey(key, &pubKey)) { debug("tpm_extraxt_pubkey() failed."); return TPM_FAIL; } if (tpm_compute_pubkey_digest(&pubKey, &blob->pubKeyDigest)) { debug("tpm_compute_pubkey_digest() failed"); free_TPM_PUBKEY(pubKey); return TPM_FAIL; } free_TPM_PUBKEY(pubKey); /* create a delegate sensitive structure */ sensitive.tag = TPM_TAG_DELEGATE_SENSITIVE; memcpy(&sensitive.authValue, &secret, sizeof(TPM_SECRET)); /* generate IV and encrypt sensitive area */ blob->additionalSize = TPM_SYM_KEY_SIZE; blob->additionalArea = tpm_malloc(blob->additionalSize); if (blob->additionalArea == NULL) { debug("tpm_malloc() failed."); return TPM_NOSPACE; } tpm_get_random_bytes(blob->additionalArea, blob->additionalSize); if (tpm_encrypt_sensitive(blob->additionalArea, blob->additionalSize, &sensitive, &blob->sensitiveArea, &blob->sensitiveSize)) { debug("tpm_encrypt_sensitive() failed."); tpm_free(blob->additionalArea); return TPM_ENCRYPT_ERROR; } /* copy public delegation information */ memcpy(&blob->pub, publicInfo, sizeof(TPM_DELEGATE_PUBLIC)); blob->pub.verificationCount = fr->verificationCount; /* compute integrity digest */ tpm_compute_key_blob_digest(blob, &blob->integrityDigest); return TPM_SUCCESS; } TPM_RESULT TPM_Delegate_CreateOwnerDelegation(BOOL increment, TPM_DELEGATE_PUBLIC *publicInfo, TPM_ENCAUTH *delAuth, TPM_AUTH *auth1, TPM_DELEGATE_OWNER_BLOB *blob) { TPM_RESULT res; TPM_SESSION_DATA *session; TPM_FAMILY_TABLE_ENTRY *fr; TPM_SECRET secret; TPM_DELEGATE_SENSITIVE sensitive; info("[TPM_Delegate_CreateOwnerDelegation]"); /* verify authorization */ session = tpm_get_auth(auth1->authHandle); if (session == NULL) return TPM_FAIL; if (session->type != TPM_ST_OSAP && session->type != TPM_ST_DSAP) { debug("session is neither of type OSAP nor DSAP"); return TPM_INVALID_AUTHHANDLE; } res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; auth1->continueAuthSession = FALSE; /* get specified family entry */ fr = tpm_get_family_row(publicInfo->familyID); if (fr == NULL) return TPM_BADINDEX; /* check delegation type */ if (publicInfo->permissions.delegateType != TPM_DEL_OWNER_BITS) { debug("invalid delegation type: %d", publicInfo->permissions.delegateType); return TPM_BAD_PARAMETER; } blob->tag = TPM_TAG_DELEGATE_OWNER_BLOB; /* verify permissions if the access was delegated */ if (session->type == TPM_ST_DSAP) { if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (session->familyID != publicInfo->familyID) return TPM_DELEGATE_FAMILY; if (((session->permissions.per1 | publicInfo->permissions.per1) != session->permissions.per1) || ((session->permissions.per2 | publicInfo->permissions.per2) != session->permissions.per2)) return TPM_AUTHFAIL; } /* increment verification count if required */ if (increment) { UINT32 i; fr->verificationCount++; debug("incrementing verificationCount to %d", fr->verificationCount); tpmData.stclear.data.ownerReference = TPM_KH_OWNER; /* invalidate all but this session */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { TPM_SESSION_DATA *s = &tpmData.stany.data.sessions[i]; if (s->type != TPM_ST_TRANSPORT && s != session) memset(s, 0, sizeof(*s)); } } /* decrypt delegation secret */ tpm_decrypt_auth_secret(*delAuth, session->sharedSecret, &session->lastNonceEven, secret); /* create a delegate sensitive structure */ sensitive.tag = TPM_TAG_DELEGATE_SENSITIVE; memcpy(&sensitive.authValue, &secret, sizeof(TPM_SECRET)); /* generate IV and encrypt sensitive area */ blob->additionalSize = TPM_SYM_KEY_SIZE; blob->additionalArea = tpm_malloc(blob->additionalSize); if (blob->additionalArea == NULL) { debug("tpm_malloc() failed."); return TPM_NOSPACE; } tpm_get_random_bytes(blob->additionalArea, blob->additionalSize); if (tpm_encrypt_sensitive(blob->additionalArea, blob->additionalSize, &sensitive, &blob->sensitiveArea, &blob->sensitiveSize)) { debug("tpm_encrypt_sensitive() failed."); tpm_free(blob->additionalArea); return TPM_ENCRYPT_ERROR; } /* copy public delegation information */ memcpy(&blob->pub, publicInfo, sizeof(TPM_DELEGATE_PUBLIC)); blob->pub.verificationCount = fr->verificationCount; /* compute integrity digest */ tpm_compute_owner_blob_digest(blob, &blob->integrityDigest); return TPM_SUCCESS; } TPM_RESULT TPM_Delegate_LoadOwnerDelegation(TPM_DELEGATE_INDEX index, TPM_DELEGATE_OWNER_BLOB *blob, TPM_AUTH *auth1) { TPM_RESULT res; TPM_SESSION_DATA *session; TPM_FAMILY_TABLE_ENTRY *fr; TPM_DIGEST blobDigest; TPM_DELEGATE_SENSITIVE sensitive; TPM_DELEGATE_TABLE_ROW *dr; BYTE *sens_buf; UINT32 i; info("TPM_Delegate_LoadOwnerDelegation()"); /* get specified family entry */ fr = tpm_get_family_row(blob->pub.familyID); if (fr == NULL) return TPM_BADINDEX; /* verify authorization */ session = tpm_get_auth(auth1->authHandle); if (session == NULL) return TPM_AUTHFAIL; if (auth1->authHandle != TPM_INVALID_AUTHHANDLE) { res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (session->type == TPM_ST_DSAP) { if (session->familyID != blob->pub.familyID) return TPM_DELEGATE_FAMILY; auth1->continueAuthSession = FALSE; } } else { if (tpmData.permanent.flags.owned) return TPM_AUTHFAIL; /* check delegate admin lock */ if (fr != NULL && (fr->flags & TPM_DELEGATE_ADMIN_LOCK)) { debug("delegate admin lock is set"); return TPM_DELEGATE_LOCK; } /* verify maximal number of writes without an owner */ if (tpmData.permanent.data.noOwnerNVWrite >= TPM_MAX_NV_WRITE_NOOWNER) return TPM_MAXNVWRITES; tpmData.permanent.data.noOwnerNVWrite++; } /* verify the integrity of the blob and decode/decrypt the sensitive data */ if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (tpmData.permanent.flags.owned) { tpm_compute_owner_blob_digest(blob, &blobDigest); if (memcmp(&blob->integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* decrypt sensitive data */ if (tpm_decrypt_sensitive(blob->additionalArea, blob->additionalSize, blob->sensitiveArea, blob->sensitiveSize, &sensitive, &sens_buf)) { debug("tpm_decrypt_sensitive() failed"); return TPM_DECRYPT_ERROR; } } else { BYTE *ptr = blob->sensitiveArea; UINT32 length = blob->sensitiveSize; if (tpm_unmarshal_TPM_DELEGATE_SENSITIVE(&ptr, &length, &sensitive) != 0) { debug("tpm_unmarshal_TPM_DELEGATE_SENSITIVE()"); return TPM_FAIL; } sens_buf = NULL; } if (sensitive.tag != TPM_TAG_DELEGATE_SENSITIVE) { tpm_free(sens_buf); return TPM_INVALID_STRUCTURE; } /* check that index is valid and copy data */ debug("index = %d", index); if (index >= TPM_NUM_DELEGATE_TABLE_ENTRY) { tpm_free(sens_buf); return TPM_BADINDEX; } dr = &tpmData.permanent.data.delegateTable.delRow[index]; dr->valid = TRUE; dr->tag = TPM_TAG_DELEGATE_TABLE_ROW; memcpy(&dr->authValue, &sensitive.authValue, sizeof(TPM_SECRET)); memcpy(&dr->pub, &blob->pub, sizeof(TPM_DELEGATE_PUBLIC)); tpm_free(sens_buf); /* invalidate all but this session */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { TPM_SESSION_DATA *s = &tpmData.stany.data.sessions[i]; if (s->type != TPM_ST_TRANSPORT && s != session) memset(s, 0, sizeof(*s)); } tpmData.stclear.data.ownerReference = TPM_KH_OWNER; return TPM_SUCCESS; } TPM_RESULT TPM_Delegate_ReadTable(UINT32 *familyTableSize, BYTE **familyTable, UINT32 *delegateTableSize, BYTE **delegateTable) { UINT32 i, length; BYTE *ptr; info("TPM_Delegate_ReadTable"); /* compute the size of the family table */ *familyTableSize = 0; *familyTable = NULL; for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { if (tpmData.permanent.data.familyTable.famRow[i].valid) { *familyTableSize += sizeof_TPM_FAMILY_TABLE_ENTRY( tpmData.permanent.data.familyTable.famRow[i]); } } debug("family table size: %d", *familyTableSize); /* allocate the table buffer and copy the family table */ if (*familyTableSize > 0) { length = *familyTableSize; ptr = *familyTable = tpm_malloc(*familyTableSize); if (*familyTable == NULL) return TPM_RESOURCES; for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { if (tpmData.permanent.data.familyTable.famRow[i].valid) { debug("writing table row %d", i); if (tpm_marshal_TPM_FAMILY_TABLE_ENTRY(&ptr, &length, &tpmData.permanent.data.familyTable.famRow[i])) { debug("tpm_marshal_TPM_FAMILY_TABLE_ENTRY() failed."); tpm_free(*familyTable); return TPM_FAIL; } } } } /* computing the size of the delegation table */ *delegateTableSize = 0; *delegateTable = NULL; for (i = 0; i < TPM_NUM_DELEGATE_TABLE_ENTRY; i++) { if (tpmData.permanent.data.delegateTable.delRow[i].valid) { *delegateTableSize += sizeof_TPM_DELEGATE_PUBLIC( tpmData.permanent.data.delegateTable.delRow[i].pub) + 4; } } debug("delegation table size: %d", *delegateTableSize); /* allocate the table buffer and copy the delegation table */ if (*delegateTableSize > 0) { length = *delegateTableSize; ptr = *delegateTable = tpm_malloc(*delegateTableSize); if (*delegateTable == NULL) { tpm_free(*familyTable); return TPM_RESOURCES; } for (i = 0; i < TPM_NUM_DELEGATE_TABLE_ENTRY; i++) { if (tpmData.permanent.data.delegateTable.delRow[i].valid) { debug("writing delegate row %d", i); if (tpm_marshal_TPM_DELEGATE_INDEX(&ptr, &length, i) || tpm_marshal_TPM_DELEGATE_PUBLIC(&ptr, &length, &tpmData.permanent.data.delegateTable.delRow[i].pub)) { debug("tpm_marshal_UINT32 or -TPM_DELEGATE_PUBLIC failed."); tpm_free(*familyTable); tpm_free(*delegateTable); return TPM_FAIL; } } } } return TPM_SUCCESS; } TPM_RESULT TPM_Delegate_UpdateVerification(UINT32 inputSize, BYTE *inputData, TPM_AUTH *auth1, UINT32 *outputSize, BYTE **outputData) { TPM_RESULT res; TPM_SESSION_DATA *session; info("TPM_Delegate_UpdateVerification()"); /* verify authorization */ session = tpm_get_auth(auth1->authHandle); if (session == NULL) return TPM_AUTHFAIL; res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* determine the type of the input data */ if (inputSize == 4) { TPM_DELEGATE_INDEX index; TPM_DELEGATE_TABLE_ROW *dr; TPM_FAMILY_TABLE_ENTRY *fr; debug("TPM_DELEGATE_TABLE_ROW"); /* unmarshal delegate index */ if (tpm_unmarshal_TPM_DELEGATE_INDEX(&inputData, &inputSize, &index)) { debug("tpm_unmarshal_TPM_DELEGATE_INDEX() failed."); return TPM_FAIL; } /* get delegate and family row */ dr = tpm_get_delegate_row(index); if (dr == NULL) return TPM_BADINDEX; fr = tpm_get_family_row(dr->pub.familyID); if (fr == NULL) return TPM_BADINDEX; /* verify permissions if the access was delegated */ if (session->type == TPM_ST_DSAP) { if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (session->familyID != fr->familyID) return TPM_DELEGATE_FAMILY; } /* update verification count */ dr->pub.verificationCount = fr->verificationCount; *outputSize = 0; *outputData = NULL; } else if (inputData[0] == (TPM_TAG_DELEGATE_OWNER_BLOB >> 8) && inputData[1] == (TPM_TAG_DELEGATE_OWNER_BLOB & 0xff)) { TPM_DELEGATE_OWNER_BLOB blob; TPM_DIGEST blobDigest; TPM_FAMILY_TABLE_ENTRY *fr; UINT32 length; BYTE *ptr; debug("TPM_DELEGATE_OWNER_BLOB"); /* unmarshal the blob */ if (tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(&inputData, &inputSize, &blob)) { debug("tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB() failed."); return TPM_FAIL; } /* validate the integrity of the blob */ tpm_compute_owner_blob_digest(&blob, &blobDigest); if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* get family row */ fr = tpm_get_family_row(blob.pub.familyID); if (fr == NULL) return TPM_BADINDEX; /* verify permissions if the access was delegated */ if (session->type == TPM_ST_DSAP) { if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (session->familyID != fr->familyID) return TPM_DELEGATE_FAMILY; } /* update verification count */ blob.pub.verificationCount = fr->verificationCount; /* update the blob digest */ tpm_compute_owner_blob_digest(&blob, &blobDigest); /* marshal the blob */ length = *outputSize = sizeof_TPM_DELEGATE_OWNER_BLOB(blob); ptr = *outputData = tpm_malloc(*outputSize); if (ptr == NULL) { debug("tpm_malloc() failed."); return TPM_NOSPACE; } if (tpm_marshal_TPM_DELEGATE_OWNER_BLOB(&ptr, &length, &blob) != 0) { debug("tpm_marshal_TPM_DELEGATE_OWNER_BLOB() failed."); tpm_free(*outputData); return TPM_FAIL; } } else if (inputData[0] == (TPM_TAG_DELEGATE_KEY_BLOB >> 8) && inputData[1] == (TPM_TAG_DELEGATE_KEY_BLOB & 0xff)) { TPM_DELEGATE_KEY_BLOB blob; TPM_DIGEST blobDigest; TPM_FAMILY_TABLE_ENTRY *fr; UINT32 length; BYTE *ptr; debug("TPM_DELEGATE_KEY_BLOB"); /* unmarshal the blob */ if (tpm_unmarshal_TPM_DELEGATE_KEY_BLOB(&inputData, &inputSize, &blob)) { debug("tpm_unmarshal_TPM_DELEGATE_KEY_BLOB() failed."); return TPM_FAIL; } /* validate the integrity of the blob */ tpm_compute_key_blob_digest(&blob, &blobDigest); if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* get family row */ fr = tpm_get_family_row(blob.pub.familyID); if (fr == NULL) return TPM_BADINDEX; /* verify permissions if the access was delegated */ if (session->type == TPM_ST_DSAP) { if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; if (session->familyID != fr->familyID) return TPM_DELEGATE_FAMILY; } /* update verification count */ blob.pub.verificationCount = fr->verificationCount; /* update the blob digest */ tpm_compute_key_blob_digest(&blob, &blobDigest); /* marshal the blob */ length = *outputSize = sizeof_TPM_DELEGATE_KEY_BLOB(blob); ptr = *outputData = tpm_malloc(*outputSize); if (ptr == NULL) { debug("tpm_malloc() failed."); return TPM_NOSPACE; } if (tpm_marshal_TPM_DELEGATE_KEY_BLOB(&ptr, &length, &blob) != 0) { debug("tpm_marshal_TPM_DELEGATE_KEY_BLOB() failed."); tpm_free(*outputData); return TPM_FAIL; } } else { debug("unsupported input structure: %02x%02x", inputData[0], inputData[1]); return TPM_BAD_PARAMETER; } return TPM_SUCCESS; } TPM_RESULT TPM_Delegate_VerifyDelegation(UINT32 delegateSize, BYTE *delegation) { info("TPM_Delegate_VerifyDelegation()"); if (delegation[0] == (TPM_TAG_DELEGATE_OWNER_BLOB >> 8) && delegation[1] == (TPM_TAG_DELEGATE_OWNER_BLOB & 0xff)) { TPM_DELEGATE_OWNER_BLOB blob; TPM_DIGEST blobDigest; TPM_FAMILY_TABLE_ENTRY *fr; TPM_DELEGATE_SENSITIVE sensitive; BYTE *sens_buf; debug("TPM_DELEGATE_OWNER_BLOB"); /* unmarshal the blob */ if (tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(&delegation, &delegateSize, &blob)) { debug("tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB() failed."); return TPM_FAIL; } /* validate the integrity of the blob */ tpm_compute_owner_blob_digest(&blob, &blobDigest); if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* get family row */ fr = tpm_get_family_row(blob.pub.familyID); if (fr == NULL) return TPM_BADINDEX; if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; /* verify verification count */ if (blob.pub.verificationCount != fr->verificationCount) return TPM_FAMILYCOUNT; /* decrypt and verify sensitive area */ if (tpm_decrypt_sensitive(blob.additionalArea, blob.additionalSize, blob.sensitiveArea, blob.sensitiveSize, &sensitive, &sens_buf)) { debug("tpm_decrypt_sensitive() failed"); return TPM_DECRYPT_ERROR; } tpm_free(sens_buf); if (sensitive.tag != TPM_TAG_DELEGATE_SENSITIVE) return TPM_BAD_PARAMETER; } else if (delegation[0] == (TPM_TAG_DELEGATE_KEY_BLOB >> 8) && delegation[1] == (TPM_TAG_DELEGATE_KEY_BLOB & 0xff)) { TPM_DELEGATE_KEY_BLOB blob; TPM_DIGEST blobDigest; TPM_FAMILY_TABLE_ENTRY *fr; TPM_DELEGATE_SENSITIVE sensitive; BYTE *sens_buf; debug("TPM_DELEGATE_KEY_BLOB"); /* unmarshal the blob */ if (tpm_unmarshal_TPM_DELEGATE_KEY_BLOB(&delegation, &delegateSize, &blob)) { debug("tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB() failed."); return TPM_FAIL; } /* validate the integrity of the blob */ tpm_compute_key_blob_digest(&blob, &blobDigest); if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0) return TPM_AUTHFAIL; /* get family row */ fr = tpm_get_family_row(blob.pub.familyID); if (fr == NULL) return TPM_BADINDEX; if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD; /* verify verification count */ if (blob.pub.verificationCount != fr->verificationCount) return TPM_FAMILYCOUNT; /* decrypt and verify sensitive area */ if (tpm_decrypt_sensitive(blob.additionalArea, blob.additionalSize, blob.sensitiveArea, blob.sensitiveSize, &sensitive, &sens_buf)) { debug("tpm_decrypt_sensitive() failed"); return TPM_DECRYPT_ERROR; } tpm_free(sens_buf); if (sensitive.tag != TPM_TAG_DELEGATE_SENSITIVE) return TPM_BAD_PARAMETER; } else { debug("unsupported input structure: %02x%02x", delegation[0], delegation[1]); return TPM_BAD_PARAMETER; } return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_deprecated.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * 2005-2008 Heiko Stamer * * 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_deprecated.c 452 2010-07-19 19:05:05Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "tpm_marshalling.h" #include "crypto/rsa.h" #include "crypto/sha1.h" #include "crypto/hmac.h" #define SAVE_KEY_CONTEXT_LABEL ((uint8_t*)"SaveKeyContext..") #define SAVE_AUTH_CONTEXT_LABEL ((uint8_t*)"SaveAuthContext.") /* * Deprecated commands ([TPM_Part3], Section 28) * This section covers the commands that were in version 1.1 but now have * new functionality in other functions. The deprecated commands are still * available in 1.2 but all new software should use the new functionality. * There is no requirement that the deprecated commands work with new * structures. */ TPM_RESULT TPM_EvictKey(TPM_KEY_HANDLE evictHandle) { info("TPM_EvictKey()"); return TPM_FlushSpecific(evictHandle, TPM_RT_KEY); } TPM_RESULT TPM_Terminate_Handle(TPM_AUTHHANDLE handle) { info("TPM_Terminate_Handle()"); return TPM_FlushSpecific(handle, TPM_RT_AUTH); } TPM_RESULT TPM_SaveKeyContext(TPM_KEY_HANDLE keyHandle, UINT32 *keyContextSize, BYTE **keyContextBlob) { TPM_RESULT res; TPM_CONTEXT_BLOB contextBlob; BYTE *ptr; UINT32 len; info("TPM_SaveKeyContext()"); res = TPM_SaveContext(keyHandle, TPM_RT_KEY, SAVE_KEY_CONTEXT_LABEL, keyContextSize, &contextBlob); if (res != TPM_SUCCESS) return res; len = *keyContextSize; *keyContextBlob = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CONTEXT_BLOB(&ptr, &len, &contextBlob)) res = TPM_FAIL; else res = TPM_SUCCESS; free_TPM_CONTEXT_BLOB(contextBlob); return res; } TPM_RESULT TPM_LoadKeyContext(UINT32 keyContextSize, BYTE *keyContextBlob, TPM_KEY_HANDLE *keyHandle) { TPM_CONTEXT_BLOB contextBlob; UINT32 len = keyContextSize; info("TPM_LoadKeyContext()"); if (tpm_unmarshal_TPM_CONTEXT_BLOB(&keyContextBlob, &len, &contextBlob)) return TPM_FAIL; return TPM_LoadContext(TPM_INVALID_HANDLE, FALSE, keyContextSize, &contextBlob, keyHandle); } TPM_RESULT TPM_SaveAuthContext(TPM_AUTHHANDLE authHandle, UINT32 *authContextSize, BYTE **authContextBlob) { TPM_RESULT res; TPM_CONTEXT_BLOB contextBlob; BYTE *ptr; UINT32 len; info("TPM_SaveAuthContext()"); res = TPM_SaveContext(authHandle, TPM_RT_KEY, SAVE_AUTH_CONTEXT_LABEL, authContextSize, &contextBlob); if (res != TPM_SUCCESS) return res; len = *authContextSize; *authContextBlob = ptr = tpm_malloc(len); if (ptr == NULL || tpm_marshal_TPM_CONTEXT_BLOB(&ptr, &len, &contextBlob)) res = TPM_FAIL; else res = TPM_SUCCESS; free_TPM_CONTEXT_BLOB(contextBlob); return res; } TPM_RESULT TPM_LoadAuthContext(UINT32 authContextSize, BYTE *authContextBlob, TPM_KEY_HANDLE *authHandle) { TPM_CONTEXT_BLOB contextBlob; UINT32 len = authContextSize; info("TPM_LoadAuthContext()"); if (tpm_unmarshal_TPM_CONTEXT_BLOB(&authContextBlob, &len, &contextBlob)) return TPM_FAIL; return TPM_LoadContext(TPM_INVALID_HANDLE, FALSE, authContextSize, &contextBlob, authHandle); } TPM_RESULT TPM_DirWriteAuth(TPM_DIRINDEX dirIndex, TPM_DIRVALUE *newContents, TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_DirWriteAuth()"); res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (dirIndex != 0) return TPM_BADINDEX; memcpy(tpmData.permanent.data.nvData + tpmData.permanent.data.nvStorage[0].dataIndex, newContents, sizeof(TPM_DIRVALUE)); return TPM_SUCCESS; } TPM_RESULT TPM_DirRead(TPM_DIRINDEX dirIndex, TPM_DIRVALUE *dirContents) { info("TPM_DirRead()"); if (dirIndex != 0) return TPM_BADINDEX; memcpy(dirContents, tpmData.permanent.data.nvData + tpmData.permanent.data.nvStorage[0].dataIndex, sizeof(TPM_DIRVALUE)); return TPM_SUCCESS; } TPM_RESULT TPM_ChangeAuthAsymStart(TPM_KEY_HANDLE idHandle, TPM_NONCE *antiReplay, TPM_KEY_PARMS *inTempKey, TPM_AUTH *auth1, TPM_CERTIFY_INFO *certifyInfo, UINT32 *sigSize, BYTE **sig, TPM_KEY_HANDLE *ephHandle, TPM_KEY *outTempKey) { TPM_RESULT res; TPM_KEY_DATA *idKey; tpm_rsa_private_key_t k1; UINT32 key_length; TPM_STORE_ASYMKEY store; TPM_KEY ephKey; UINT32 len, size; BYTE *ptr, *buf; info("TPM_ChangeAuthAsymStart()"); /* 1. The TPM SHALL verify the AuthData to use the TPM identity key held in idHandle. The TPM MUST verify that the key is a TPM identity key. */ /* get identity key */ idKey = tpm_get_key(idHandle); if (idKey == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || idKey->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, idKey->usageAuth, idHandle); if (res != TPM_SUCCESS) return res; } /* verify key parameters */ if (idKey->keyUsage != TPM_KEY_IDENTITY) return TPM_INVALID_KEYUSAGE; /* 2. The TPM SHALL validate the algorithm parameters for the key to create from the tempKey parameter. */ /* 3. Recommended key type is RSA */ /* 4. Minimum RSA key size MUST is 512 bits, recommended RSA key size is 1024 */ /* 5. For other key types the minimum key size strength MUST be comparable to RSA 512 */ /* 6. If the TPM is not designed to create a key of the requested type, return the error code TPM_BAD_KEY_PROPERTY */ if (inTempKey->algorithmID != TPM_ALG_RSA || inTempKey->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || inTempKey->parmSize == 0 || inTempKey->parms.rsa.keyLength < 512 || inTempKey->parms.rsa.numPrimes != 2 || inTempKey->parms.rsa.exponentSize != 0) return TPM_BAD_KEY_PROPERTY; /* 7. The TPM SHALL create a new key (k1) in accordance with the algorithm parameter. The newly created key is pointed to by ephHandle. */ /* generate key */ key_length = inTempKey->parms.rsa.keyLength; if (tpm_rsa_generate_key(&k1, key_length)) { debug("TPM_ChangeAuthAsymStart(): tpm_rsa_generate_key() failed."); return TPM_FAIL; } /* setup private key store */ store.payload = TPM_PT_ASYM; memcpy(store.usageAuth, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_SECRET)); memcpy(store.migrationAuth, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_SECRET)); store.privKey.keyLength = key_length >> 4; store.privKey.key = tpm_malloc(store.privKey.keyLength); if (store.privKey.key == NULL) { tpm_rsa_release_private_key(&k1); return TPM_NOSPACE; } tpm_rsa_export_prime1(&k1, store.privKey.key, NULL); /* setup ephKey */ ephKey.tag = 0x0101; ephKey.fill = 0x0000; ephKey.keyUsage = TPM_KEY_AUTHCHANGE; ephKey.keyFlags = TPM_KEY_FLAG_VOLATILE; ephKey.authDataUsage = TPM_AUTH_NEVER; ephKey.algorithmParms.algorithmID = inTempKey->algorithmID; ephKey.algorithmParms.encScheme = inTempKey->encScheme; ephKey.algorithmParms.sigScheme = inTempKey->sigScheme; ephKey.algorithmParms.parmSize = inTempKey->parmSize; switch (ephKey.algorithmParms.algorithmID) { case TPM_ALG_RSA: ephKey.algorithmParms.parms.rsa.keyLength = inTempKey->parms.rsa.keyLength; ephKey.algorithmParms.parms.rsa.numPrimes = inTempKey->parms.rsa.numPrimes; ephKey.algorithmParms.parms.rsa.exponentSize = inTempKey->parms.rsa.exponentSize; break; default: tpm_rsa_release_private_key(&k1); return TPM_BAD_KEY_PROPERTY; } ephKey.PCRInfoSize = 0; ephKey.pubKey.keyLength = key_length >> 3; ephKey.pubKey.key = tpm_malloc(ephKey.pubKey.keyLength); if (ephKey.pubKey.key == NULL) { tpm_rsa_release_private_key(&k1); tpm_free(store.privKey.key); return TPM_NOSPACE; } tpm_rsa_export_modulus(&k1, ephKey.pubKey.key, NULL); tpm_rsa_release_private_key(&k1); ephKey.encDataSize = key_length >> 3; ephKey.encData = tpm_malloc(ephKey.encDataSize); if (ephKey.encData == NULL) { tpm_free(store.privKey.key); tpm_free(ephKey.pubKey.key); return TPM_NOSPACE; } if (tpm_compute_key_digest(&ephKey, &store.pubDataDigest)) { tpm_free(store.privKey.key); tpm_free(ephKey.pubKey.key); tpm_free(ephKey.encData); debug("TPM_ChangeAuthAsymStart(): tpm_compute_key_digest() failed."); return TPM_FAIL; } if (tpm_encrypt_private_key(&tpmData.permanent.data.srk, &store, ephKey.encData, &ephKey.encDataSize)) { tpm_free(store.privKey.key); tpm_free(ephKey.pubKey.key); tpm_free(ephKey.encData); debug("TPM_ChangeAuthAsymStart(): tpm_encrypt_private_key() failed."); return TPM_ENCRYPT_ERROR; } tpm_free(store.privKey.key); /* assign a handle and store ephKey by calling internal_TPM_LoadKey() */ res = internal_TPM_LoadKey(&ephKey, ephHandle); if (res != TPM_SUCCESS) { tpm_free(ephKey.pubKey.key); tpm_free(ephKey.encData); return res; } tpm_free(ephKey.pubKey.key); tpm_free(ephKey.encData); /* 8. The TPM SHALL fill in all fields in tempKey using k1 for the information. The TPM_KEY->encSize MUST be 0. */ outTempKey->tag = ephKey.tag; outTempKey->fill = ephKey.fill; outTempKey->keyUsage = ephKey.keyUsage; outTempKey->keyFlags = ephKey.keyFlags; outTempKey->authDataUsage = ephKey.authDataUsage; outTempKey->algorithmParms.algorithmID = ephKey.algorithmParms.algorithmID; outTempKey->algorithmParms.encScheme = ephKey.algorithmParms.encScheme; outTempKey->algorithmParms.sigScheme = ephKey.algorithmParms.sigScheme; outTempKey->algorithmParms.parmSize = ephKey.algorithmParms.parmSize; outTempKey->algorithmParms.parms.rsa.keyLength = ephKey.algorithmParms.parms.rsa.keyLength; outTempKey->algorithmParms.parms.rsa.numPrimes = ephKey.algorithmParms.parms.rsa.numPrimes; outTempKey->algorithmParms.parms.rsa.exponentSize = ephKey.algorithmParms.parms.rsa.exponentSize; outTempKey->PCRInfoSize = ephKey.PCRInfoSize; outTempKey->pubKey.keyLength = ephKey.pubKey.keyLength; outTempKey->pubKey.key = tpm_malloc(outTempKey->pubKey.keyLength); if (outTempKey->pubKey.key == NULL) return TPM_NOSPACE; memcpy(outTempKey->pubKey.key, ephKey.pubKey.key, outTempKey->pubKey.keyLength); outTempKey->encDataSize = 0; outTempKey->encData = NULL; /* 9. The TPM SHALL fill in certifyInfo using k1 for the information. The certifyInfo->data field is supplied by the antiReplay. */ /* "Version" field is set according to the deprecated TPM_VERSION structure from the old v1.1 specification. */ memcpy(&certifyInfo->tag, &tpmData.permanent.data.version, 2); memcpy(&certifyInfo->fill, &tpmData.permanent.data.version + 2, 1); memcpy(&certifyInfo->payloadType, &tpmData.permanent.data.version + 3, 1); /* Other fields are filled according to Section 27.4.1 [TPM, Part 3]. */ certifyInfo->keyUsage = ephKey.keyUsage; certifyInfo->keyFlags = ephKey.keyFlags; certifyInfo->authDataUsage = ephKey.authDataUsage; certifyInfo->algorithmParms.algorithmID = ephKey.algorithmParms.algorithmID; certifyInfo->algorithmParms.encScheme = ephKey.algorithmParms.encScheme; certifyInfo->algorithmParms.sigScheme = ephKey.algorithmParms.sigScheme; certifyInfo->algorithmParms.parmSize = ephKey.algorithmParms.parmSize; certifyInfo->algorithmParms.parms.rsa.keyLength = ephKey.algorithmParms.parms.rsa.keyLength; certifyInfo->algorithmParms.parms.rsa.numPrimes = ephKey.algorithmParms.parms.rsa.numPrimes; certifyInfo->algorithmParms.parms.rsa.exponentSize = ephKey.algorithmParms.parms.rsa.exponentSize; memcpy(&certifyInfo->pubkeyDigest, &store.pubDataDigest, sizeof(TPM_DIGEST)); memcpy(&certifyInfo->data, antiReplay, sizeof(TPM_NONCE)); certifyInfo->parentPCRStatus = FALSE; certifyInfo->PCRInfoSize = 0; /* 10. The TPM then signs the certifyInfo parameter using the key pointed to by idHandle. The resulting signed blob is returned in sig parameter. */ size = len = sizeof_TPM_CERTIFY_INFO((*certifyInfo)); buf = ptr = tpm_malloc(size); if (buf == NULL) { return TPM_NOSPACE; } if (tpm_marshal_TPM_CERTIFY_INFO(&ptr, &len, certifyInfo) || (len != 0)) { debug("TPM_ChangeAuthAsymStart(): tpm_marshal_TPM_CERTIFY_INFO() failed."); tpm_free(buf); return TPM_FAIL; } res = tpm_sign(idKey, auth1, FALSE, buf, size, sig, sigSize); tpm_free(buf); return res; } TPM_RESULT TPM_ChangeAuthAsymFinish(TPM_KEY_HANDLE parentHandle, TPM_KEY_HANDLE ephHandle, TPM_ENTITY_TYPE entityType, TPM_HMAC *newAuthLink, UINT32 newAuthSize, BYTE *encNewAuth, UINT32 encDataSize, BYTE *encData, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData, TPM_NONCE *saltNonce, TPM_DIGEST *changeProof) { TPM_RESULT res; TPM_KEY_DATA *parentKey, *ephKey; TPM_SEALED_DATA e1_seal; TPM_STORE_ASYMKEY e1_store; BYTE *e1_seal_buf, *e1_key_buf; int scheme; TPM_CHANGEAUTH_VALIDATE a1; tpm_hmac_ctx_t hmac_ctx; UINT32 len; size_t size; BYTE *ptr, *buf; TPM_SECRET oldAuthSecret; TPM_HMAC b1; info("TPM_ChangeAuthAsymFinish()"); /* 1. The TPM SHALL validate that the authHandle parameter authorizes use of the key in parentHandle. */ /* get parent key */ parentKey = tpm_get_key(parentHandle); if (parentKey == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || parentKey->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, parentKey->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; } /* get ephemeral key */ ephKey = tpm_get_key(ephHandle); if (ephKey == NULL) return TPM_INVALID_KEYHANDLE; /* 2. The encData field MUST be the encData field from TPM_STORED_DATA or TPM_KEY. */ if (encDataSize != (parentKey->key.size >> 3)) return TPM_BAD_PARAMETER; /* 3. The TPM SHALL create e1 by decrypting the entity held in the encData parameter. */ switch (entityType) { case TPM_ET_DATA: /* decrypt seal data */ if (tpm_decrypt_sealed_data(parentKey, encData, encDataSize, &e1_seal, &e1_seal_buf)) return TPM_DECRYPT_ERROR; memcpy(oldAuthSecret, e1_seal.authData, sizeof(TPM_SECRET)); tpm_free(e1_seal_buf); break; case TPM_ET_KEY: /* decrypt key data */ if (tpm_decrypt_private_key(parentKey, encData, encDataSize, &e1_store, &e1_key_buf, NULL)) return TPM_DECRYPT_ERROR; memcpy(oldAuthSecret, e1_store.usageAuth, sizeof(TPM_SECRET)); tpm_free(e1_key_buf); break; default: return TPM_BAD_PARAMETER; } /* 4. The TPM SHALL create a1 by decrypting encNewAuth using the ephHandle->TPM_KEY_AUTHCHANGE private key. a1 is a structure of type TPM_CHANGEAUTH_VALIDATE. */ switch (ephKey->encScheme) { case TPM_ES_RSAESOAEP_SHA1_MGF1: scheme = RSA_ES_OAEP_SHA1; break; case TPM_ES_RSAESPKCSv15: scheme = RSA_ES_PKCSV15; break; default: return TPM_BAD_PARAMETER; } len = newAuthSize; buf = ptr = tpm_malloc(len); if (buf == NULL) return TPM_NOSPACE; if (tpm_rsa_decrypt(&ephKey->key, scheme, encNewAuth, newAuthSize, buf, &size) || (len = size) == 0 || tpm_unmarshal_TPM_CHANGEAUTH_VALIDATE(&ptr, &len, &a1)) { debug("TPM_ChangeAuthAsymFinish(): tpm_rsa_decrypt() failed."); tpm_free(buf); return TPM_DECRYPT_ERROR; } tpm_free(buf); /* 5. The TPM SHALL create b1 by performing the following HMAC calculation: b1 = HMAC(a1->newAuthSecret). The secret for this calculation is encData->currentAuth. This means that b1 is a value built from the current AuthData value (encData->currentAuth) and the new AuthData value (a1->newAuthSecret). */ tpm_hmac_init(&hmac_ctx, oldAuthSecret, sizeof(TPM_SECRET)); tpm_hmac_update(&hmac_ctx, a1.newAuthSecret, sizeof(TPM_SECRET)); tpm_hmac_final(&hmac_ctx, b1.digest); /* 6. The TPM SHALL compare b1 with newAuthLink. The TPM SHALL indicate a failure if the values do not match. */ if (memcmp(&b1, newAuthLink, sizeof(TPM_HMAC))) { debug("TPM_ChangeAuthAsymFinish(): newAuthLink value does not match."); return TPM_FAIL; } /* 7. The TPM SHALL replace e1->authData with a1->newAuthSecret */ switch (entityType) { case TPM_ET_DATA: memcpy(e1_seal.authData, a1.newAuthSecret, sizeof(TPM_SECRET)); break; case TPM_ET_KEY: memcpy(e1_store.usageAuth, a1.newAuthSecret, sizeof(TPM_SECRET)); break; } /* 8. The TPM SHALL encrypt e1 using the appropriate functions for the entity type. The key to encrypt with is parentHandle. */ switch (entityType) { case TPM_ET_DATA: if (tpm_encrypt_sealed_data(parentKey, &e1_seal, *outData, outDataSize)) { tpm_free(outData); return TPM_ENCRYPT_ERROR; } break; case TPM_ET_KEY: if (tpm_encrypt_private_key(parentKey, &e1_store, *outData, outDataSize)) { tpm_free(outData); return TPM_ENCRYPT_ERROR; } break; } /* 9. The TPM SHALL create slatNonce by taking the next 20 bytes from the TPM RNG. */ tpm_get_random_bytes(saltNonce->nonce, sizeof(TPM_NONCE)); /* 10. The TPM SHALL create changeProof a HMAC of (saltNonce concatenated with a1->n1) using a1->newAuthSecret as the HMAC secret. */ tpm_hmac_init(&hmac_ctx, a1.newAuthSecret, sizeof(a1.newAuthSecret)); tpm_hmac_update(&hmac_ctx, saltNonce->nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&hmac_ctx, a1.n1.nonce, sizeof(TPM_NONCE)); tpm_hmac_final(&hmac_ctx, changeProof->digest); /* 11. The TPM MUST destroy the TPM_KEY_AUTHCHANGE key associated with the authorization session. */ tpm_rsa_release_private_key(&ephKey->key); memset(ephKey, 0, sizeof(*ephKey)); tpm_invalidate_sessions(ephHandle); return TPM_SUCCESS; } TPM_RESULT TPM_Reset() { int i; info("TPM_Reset()"); /* invalidate all authorization sessions */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { TPM_SESSION_DATA *session = &tpmData.stany.data.sessions[i]; if (session->type == TPM_ST_OIAP || session->type == TPM_ST_OSAP) memset(session, 0, sizeof(*session)); } return TPM_SUCCESS; } TPM_RESULT TPM_CertifySelfTest(TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_AUTH *auth1, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; BYTE buf[35]; info("TPM_CertifySelfTest()"); key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* perform self test */ res = TPM_SelfTestFull(); if (res != TPM_SUCCESS) return res; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY && key->keyUsage != TPM_KEY_IDENTITY) return TPM_INVALID_KEYUSAGE; /* not neccessary, because a vendor specific signature is allowed if (key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) return TPM_BAD_SCHEME; */ /* setup and sign result */ memcpy(&buf, "Test Passed", 11); memcpy(&buf[11], antiReplay->nonce, sizeof(TPM_NONCE)); memcpy(&buf[31], "\x52\x00\x00\x00", 4); return tpm_sign(key, auth1, FALSE, buf, sizeof(buf), sig, sigSize); } TPM_RESULT TPM_OwnerReadPubek(TPM_AUTH *auth1, TPM_PUBKEY *pubEndorsementKey) { TPM_RESULT res; info("TPM_OwnerReadPubek()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; res = tpm_get_pubek(pubEndorsementKey); if (res != TPM_SUCCESS) return res; return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_emulator.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_emulator.h 463 2011-06-08 14:25:04Z mast $ */ #ifndef _TPM_EMULATOR_H_ #define _TPM_EMULATOR_H_ #include "config.h" #include "tpm_emulator_extern.h" #define TPM_MANUFACTURER 0x4554485A /* 'ETHZ' */ /** * configuration flags */ #define TPM_CONF_STRONG_PERSISTENCE 0x01 #define TPM_CONF_GENERATE_EK 0x02 #define TPM_CONF_GENERATE_SEED_DAA 0x04 #define TPM_CONF_USE_INTERNAL_PRNG 0x08 #define TPM_CONF_ALLOW_PRNG_STATE_SETTING 0x10 /** * tpm_emulator_init - initialises and starts the TPM emulator * @startup: [in] startup mode * @conf: [in] tpm configuration flags * @Returns: 0 on success, -1 otherwise */ int tpm_emulator_init(uint32_t startup, uint32_t conf); /** * tpm_emulator_shutdown - shuts the TPM emulator down */ void tpm_emulator_shutdown(void); /** * tpm_handle_command - handles (i.e., executes) TPM commands * @in: [in] incoming TPM command * @in_size: [in] total number of input bytes * @out: [inout] outgoing TPM result * @out_size: [inout] total number of output bytes * @Returns: 0 on success, -1 otherwise * * Description: Handles (i.e., executes) TPM commands. The parameters * out and out_size determine the output buffer and its capacity, * respectively. If out is NULL, the required memory is allocated * internally and has to be released by means of tpm_free() after * its usage. In case of an error, all internally allocated memory * is released and the the state of out and out_size is unspecified. */ int tpm_handle_command(const uint8_t *in, uint32_t in_size, uint8_t **out, uint32_t *out_size); #endif /* _TPM_EMULATOR_H_ */ ================================================ FILE: tpm/tpm_emulator_extern.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_emulator_extern.c 477 2012-04-28 09:15:26Z mast $ */ #include "tpm_emulator_extern.h" #include "config.h" #ifndef TPM_NO_EXTERN #include #include #include #include #include #include #include #include #include const char *tpm_storage_file = TPM_STORAGE_NAME; const char *tpm_log_file = TPM_LOG_FILE; const char *tpm_random_device = "/dev/urandom"; static int mkdirs(const char *path) { char *copy = strdup(path); char *p = strchr(copy + 1, '/'); while (p != NULL) { *p = '\0'; #if defined(_WIN32) || defined(_WIN64) if ((mkdir(copy) == -1) && (errno != EEXIST)) { #else if ((mkdir(copy, 0755) == -1) && (errno != EEXIST)) { #endif free(copy); return errno; } *p = '/'; p = strchr(p + 1, '/'); } free(copy); return 0; } #if defined(_WIN32) || defined(_WIN64) #include #include static HCRYPTPROV rand_ch; static int _tpm_extern_init() { info("_tpm_extern_init()"); mkdirs(tpm_storage_file); mkdirs(tpm_log_file); debug("initializing crypto context for RNG"); BOOL res = CryptAcquireContext(&rand_ch, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT); if (!res) { /* try it again with CRYPT_NEWKEYSET enabled */ res = CryptAcquireContext(&rand_ch, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_NEWKEYSET); } if (!res) { error("CryptAcquireContext() failed: %d", GetLastError()); return -1; } return 0; } void _tpm_extern_release() { info("_tpm_extern_release()"); CryptReleaseContext(rand_ch, 0); } void _tpm_get_extern_random_bytes(void *buf, size_t nbytes) { CryptGenRandom(rand_ch, nbytes, (BYTE*)buf); } #else static int rand_fh = -1; static int _tpm_extern_init() { info("_tpm_extern_init()"); mkdirs(tpm_storage_file); mkdirs(tpm_log_file); debug("openening random device %s", tpm_random_device); rand_fh = open(tpm_random_device, O_RDONLY); if (rand_fh < 0) { error("open(%s) failed: %s", tpm_random_device, strerror(errno)); return -1; } return 0; } static void _tpm_extern_release() { info("_tpm_extern_release()"); if (rand_fh != -1) close(rand_fh); } static void _tpm_get_extern_random_bytes(void *buf, size_t nbytes) { uint8_t *p = (uint8_t*)buf; ssize_t res; while (nbytes > 0) { res = read(rand_fh, p, nbytes); if (res > 0) { nbytes -= res; p += res; } } } #endif static void *_tpm_malloc(size_t size) { return malloc(size); } static void _tpm_free(/*const*/ void *ptr) { if (ptr != NULL) free((void*)ptr); } static void _tpm_log(int priority, const char *fmt, ...) { FILE *fh; va_list ap; time_t tv; struct tm t; va_start(ap, fmt); fh = fopen(tpm_log_file, "a"); if (fh != NULL) { time(&tv); #if defined(_WIN32) || defined(_WIN64) memcpy(&t, localtime(&tv), sizeof(t)); #else localtime_r(&tv, &t); #endif fprintf(fh, "%04d-%02d-%02d %02d:%02d:%02d ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); vfprintf(fh, fmt, ap); fclose(fh); } va_end(ap); } static uint64_t _tpm_get_ticks(void) { static uint64_t old_t = 0; uint64_t new_t, res_t; struct timeval tv; gettimeofday(&tv, NULL); new_t = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; res_t = (old_t > 0) ? new_t - old_t : 0; old_t = new_t; return res_t; } static int _tpm_write_to_storage(uint8_t *data, size_t data_length) { int fh; ssize_t res; #if defined(_WIN32) || defined(_WIN64) fh = open(tpm_storage_file, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, S_IRUSR | S_IWUSR); #else fh = open(tpm_storage_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); #endif if (fh < 0) return -1; while (data_length > 0) { res = write(fh, data, data_length); if (res < 0) { close(fh); return -1; } data_length -= res; data += res; } close(fh); return 0; } 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; } int (*tpm_extern_init)(void) = _tpm_extern_init; void (*tpm_extern_release)(void) = _tpm_extern_release; void* (*tpm_malloc)(size_t size) = _tpm_malloc; void (*tpm_free)(/*const*/ void *ptr) = _tpm_free; void (*tpm_log)(int priority, const char *fmt, ...) = _tpm_log; void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes) = _tpm_get_extern_random_bytes; uint64_t (*tpm_get_ticks)(void) = _tpm_get_ticks; int (*tpm_write_to_storage)(uint8_t *data, size_t data_length) = _tpm_write_to_storage; int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = _tpm_read_from_storage; #else /* TPM_NO_EXTERN */ int (*tpm_extern_init)(void) = NULL; void (*tpm_extern_release)(void) = NULL; void* (*tpm_malloc)(size_t size) = NULL; void (*tpm_free)(/*const*/ void *ptr) = NULL; void (*tpm_log)(int priority, const char *fmt, ...) = NULL; void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes) = NULL; uint64_t (*tpm_get_ticks)(void) = NULL; int (*tpm_write_to_storage)(uint8_t *data, size_t data_length) = NULL; int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length) = NULL; #endif /* TPM_NO_EXTERN */ ================================================ FILE: tpm/tpm_emulator_extern.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_emulator_extern.h 440 2010-03-17 22:53:07Z mast $ */ #ifndef _TPM_EMULATOR_EXTERN_H_ #define _TPM_EMULATOR_EXTERN_H_ #include #include #include /* log functions */ enum { TPM_LOG_DEBUG, TPM_LOG_INFO, TPM_LOG_ERROR }; void (*tpm_log)(int priority, const char *fmt, ...); #if defined(_WIN32) || defined(_WIN64) #define __BFILE__ ((strrchr(__FILE__, '\\') ? : __FILE__ - 1) + 1) #else #define __BFILE__ ((strrchr(__FILE__, '/') ? : __FILE__ - 1) + 1) #endif #define debug(fmt, ...) tpm_log(TPM_LOG_DEBUG, "%s:%d: Debug: " fmt "\n", \ __BFILE__, __LINE__, ## __VA_ARGS__) #define info(fmt, ...) tpm_log(TPM_LOG_INFO, "%s:%d: Info: " fmt "\n", \ __BFILE__, __LINE__, ## __VA_ARGS__) #define error(fmt, ...) tpm_log(TPM_LOG_ERROR, "%s:%d: Error: " fmt "\n", \ __BFILE__, __LINE__, ## __VA_ARGS__) /* initialization */ int (*tpm_extern_init)(void); void (*tpm_extern_release)(void); /* memory allocation */ void* (*tpm_malloc)(size_t size); void (*tpm_free)(/*const*/ void *ptr); /* random numbers */ void (*tpm_get_extern_random_bytes)(void *buf, size_t nbytes); /* usec since last call */ uint64_t (*tpm_get_ticks)(void); /* file handling */ int (*tpm_write_to_storage)(uint8_t *data, size_t data_length); int (*tpm_read_from_storage)(uint8_t **data, size_t *data_length); #endif /* _TPM_EMULATOR_EXTERN_H_ */ ================================================ FILE: tpm/tpm_error.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_error.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_structures.h" const char *tpm_error_to_string(TPM_RESULT res) { switch (res) { case TPM_SUCCESS: return "Successful completion of the operation."; case TPM_AUTHFAIL: return "Authentication failed."; case TPM_BADINDEX: return "The index to a PCR, DIR or other register is incorrect."; case TPM_BAD_PARAMETER: return "One or more parameter is bad."; case TPM_AUDITFAILURE: return "An operation completed successfully but the auditing of " "that operation failed."; case TPM_CLEAR_DISABLED: return "The clear disable flag is set and all clear operations now " "require physical access."; case TPM_DEACTIVATED: return "The TPM is deactivated."; case TPM_DISABLED: return "The TPM is disabled."; case TPM_DISABLED_CMD: return "The target command has been disabled."; case TPM_FAIL: return "The operation failed."; case TPM_BAD_ORDINAL: return "The ordinal was unknown or inconsistent."; case TPM_INSTALL_DISABLED: return "The ability to install an owner is disabled."; case TPM_INVALID_KEYHANDLE: return "The key handle can not be interpreted."; case TPM_KEYNOTFOUND: return "The key handle points to an invalid key."; case TPM_INAPPROPRIATE_ENC: return "Unacceptable encryption scheme."; case TPM_MIGRATEFAIL: return "Migration authorization failed."; case TPM_INVALID_PCR_INFO: return "PCR information could not be interpreted."; case TPM_NOSPACE: return "No room to load key."; case TPM_NOSRK: return "There is no SRK set."; case TPM_NOTSEALED_BLOB: return "An encrypted blob is invalid or was not created by this TPM."; case TPM_OWNER_SET: return "There is already an Owner."; case TPM_RESOURCES: return "The TPM has insufficient internal resources to perform the " "requested action."; case TPM_SHORTRANDOM: return "A random string was too short."; case TPM_SIZE: return "The TPM does not have the space to perform the operation."; case TPM_WRONGPCRVAL: return "The named PCR value does not match the current PCR value."; case TPM_BAD_PARAM_SIZE: return "The paramSize argument to the command has the incorrect value."; case TPM_SHA_THREAD: return "There is no existing SHA-1 thread."; case TPM_SHA_ERROR: return "The calculation is unable to proceed because the existing SHA-1 " "thread has already encountered an error."; case TPM_FAILEDSELFTEST: return "Self-test has failed and the TPM has shutdown."; case TPM_AUTH2FAIL: return "The authorization for the second key in a 2 key function failed " "authorization."; case TPM_BADTAG: return "The tag value sent to for a command is invalid."; case TPM_IOERROR: return "An IO error occurred transmitting information to the TPM."; case TPM_ENCRYPT_ERROR: return "The encryption process had a problem."; case TPM_DECRYPT_ERROR: return "The decryption process did not complete."; case TPM_INVALID_AUTHHANDLE: return "An invalid handle was used."; case TPM_NO_ENDORSEMENT: return "The TPM does not a EK installed."; case TPM_INVALID_KEYUSAGE: return "The usage of a key is not allowed."; case TPM_WRONG_ENTITYTYPE: return "The submitted entity type is not allowed."; case TPM_INVALID_POSTINIT: return "The command was received in the wrong sequence relative to " "TPM_Init and a subsequent TPM_Startup."; case TPM_INAPPROPRIATE_SIG: return "Signed data cannot include additional DER information."; case TPM_BAD_KEY_PROPERTY: return "The key properties in TPM_KEY_PARMs are not supported " "by this TPM."; case TPM_BAD_MIGRATION: return "The migration properties of this key are incorrect."; case TPM_BAD_SCHEME: return "The signature or encryption scheme for this key is incorrect " "or not permitted in this situation."; case TPM_BAD_DATASIZE: return "The size of the data (or blob) parameter is bad or " "inconsistent with the referenced key."; case TPM_BAD_MODE: return "A mode parameter is bad, such as capArea or subCapArea for " "TPM_GetCapability, physicalPresence parameter for " "TPM_PhysicalPresence, or migrationType for TPM_CreateMigrationBlob."; case TPM_BAD_PRESENCE: return "Either the physicalPresence or physicalPresenceLock bits " "have the wrong value."; case TPM_BAD_VERSION: return "The TPM cannot perform this version of the capability."; case TPM_NO_WRAP_TRANSPORT: return "The TPM does not allow for wrapped transport sessions."; case TPM_AUDITFAIL_UNSUCCESSFUL: return "TPM audit construction failed and the underlying command was " "returning a failure code also."; case TPM_AUDITFAIL_SUCCESSFUL: return "TPM audit construction failed and the underlying command was " "returning success."; case TPM_NOTRESETABLE: return "Attempt to reset a PCR register that does not have the " "resettable attribute."; case TPM_NOTLOCAL: return "Attempt to reset a PCR register that requires locality and " "locality modifier not part of command transport."; case TPM_BAD_TYPE: return "Make identity blob not properly typed."; case TPM_INVALID_RESOURCE: return "When saving context identified resource type does not match " "actual resource."; case TPM_NOTFIPS: return "The TPM is attempting to execute a command only available " "when in FIPS mode."; case TPM_INVALID_FAMILY: return "The command is attempting to use an invalid family ID."; case TPM_NO_NV_PERMISSION: return "The permission to manipulate the NV storage is not available."; case TPM_REQUIRES_SIGN: return "The operation requires a signed command."; case TPM_KEY_NOTSUPPORTED: return "Wrong operation to load an NV key."; case TPM_AUTH_CONFLICT: return "NV_LoadKey blob requires both owner and blob authorization."; case TPM_AREA_LOCKED: return "The NV area is locked and not writable."; case TPM_BAD_LOCALITY: return "The locality is incorrect for the attempted operation."; case TPM_READ_ONLY: return "The NV area is read only and can't be written to."; case TPM_PER_NOWRITE: return "There is no protection on the write to the NV area."; case TPM_FAMILYCOUNT: return "The family count value does not match."; case TPM_WRITE_LOCKED: return "The NV area has already been written to."; case TPM_BAD_ATTRIBUTES: return "The NV area attributes conflict."; case TPM_INVALID_STRUCTURE: return "The structure tag and version are invalid or inconsistent."; case TPM_KEY_OWNER_CONTROL: return "The key is under control of the TPM Owner and can only be " "evicted by the TPM Owner."; case TPM_BAD_COUNTER: return "The counter handle is incorrect."; case TPM_NOT_FULLWRITE: return "The write is not a complete write of the area."; case TPM_CONTEXT_GAP: return "The gap between saved context counts is too large."; case TPM_MAXNVWRITES: return "The maximum number of NV writes without an " "owner has been exceeded."; case TPM_NOOPERATOR: return "No operator AuthData value is set."; case TPM_RESOURCEMISSING: return "The resource pointed to by context is not loaded."; case TPM_DELEGATE_LOCK: return "The delegate administration is locked."; case TPM_DELEGATE_FAMILY: return "Attempt to manage a family other then the delegated family."; case TPM_DELEGATE_ADMIN: return "Delegation table management not enabled."; case TPM_TRANSPORT_NOTEXCLUSIVE: return "There was a command executed outside of an exclusive " "transport session."; case TPM_OWNER_CONTROL: return "Attempt to context save a owner evict controlled key."; case TPM_DAA_RESOURCES: return "The DAA command has no resources available to " "execute the command."; case TPM_DAA_INPUT_DATA0: return "The consistency check on DAA parameter inputData0 has failed."; case TPM_DAA_INPUT_DATA1: return "The consistency check on DAA parameter inputData1 has failed."; case TPM_DAA_ISSUER_SETTINGS: return "The consistency check on DAA_issuerSettings has failed."; case TPM_DAA_TPM_SETTINGS: return "The consistency check on DAA_tpmSpecific has failed."; case TPM_DAA_STAGE: return "The atomic process indicated by the submitted DAA command " "is not the expected process."; case TPM_DAA_ISSUER_VALIDITY: return "The issuer's validity check has detected an inconsistency."; case TPM_DAA_WRONG_W: return "The consistency check on w has failed."; case TPM_BAD_HANDLE: return "The handle is incorrect."; case TPM_BAD_DELEGATE: return "Delegation is not correct."; case TPM_BADCONTEXT: return "The context blob is invalid."; case TPM_TOOMANYCONTEXTS: return "Too many contexts held by the TPM."; case TPM_MA_TICKET_SIGNATURE: return "Migration authority signature validation failure."; case TPM_MA_DESTINATION: return "Migration destination not authenticated."; case TPM_MA_SOURCE: return "Migration source incorrect."; case TPM_MA_AUTHORITY: return "Incorrect migration authority."; case TPM_PERMANENTEK: return "Attempt to revoke the EK and the EK is not revocable."; case TPM_BAD_SIGNATURE: return "Bad signature of CMK ticket."; case TPM_NOCONTEXTSPACE: return "There is no room in the context list for additional contexts."; case TPM_RETRY: return "The TPM is too busy to respond to the command immediately, " "but the command could be resubmitted at a later time."; default: return "Unknown TPM error"; } } ================================================ FILE: tpm/tpm_eviction.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_eviction.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" #include "crypto/rsa.h" /* * Eviction ([TPM_Part3], Section 22) * The TPM has numerous resources held inside of the TPM that may need * eviction. The need for eviction occurs when the number or resources * in use by the TPM exceed the available space. In version 1.1 there were * separate commands to evict separate resource types. This new command * set uses the resource types defined for context saving and creates a * generic command that will evict all resource types. */ static void dump_sessions(void) { int i; for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) { debug("session[%d] = %08x", i, INDEX_TO_AUTH_HANDLE(i)); } } } TPM_RESULT TPM_FlushSpecific(TPM_HANDLE handle, TPM_RESOURCE_TYPE resourceType) { TPM_SESSION_DATA *session; TPM_DAA_SESSION_DATA *sessionDAA; TPM_KEY_DATA *key; int i; info("TPM_FlushSpecific()"); debug("handle = %08x, resourceType = %08x", handle, resourceType); switch (resourceType) { case TPM_RT_CONTEXT: for (i = 0; i < TPM_MAX_SESSION_LIST; i++) if (tpmData.stany.data.contextList[i] == handle) break; if (i != TPM_MAX_SESSION_LIST) tpmData.stany.data.contextList[i] = 0; return TPM_SUCCESS; case TPM_RT_KEY: key = tpm_get_key(handle); if (key != NULL) { if (key->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) return TPM_KEY_OWNER_CONTROL; if (handle == TPM_KH_SRK) return TPM_FAIL; tpm_rsa_release_private_key(&key->key); memset(key, 0, sizeof(*key)); tpm_invalidate_sessions(handle); } return TPM_SUCCESS; case TPM_RT_HASH: case TPM_RT_COUNTER: case TPM_RT_DELEGATE: return TPM_INVALID_RESOURCE; case TPM_RT_AUTH: session = tpm_get_auth(handle); if (session != NULL) memset(session, 0, sizeof(*session)); dump_sessions(); return TPM_SUCCESS; case TPM_RT_TRANS: session = tpm_get_transport(handle); if (session != NULL) memset(session, 0, sizeof(*session)); dump_sessions(); return TPM_SUCCESS; case TPM_RT_DAA_TPM: sessionDAA = tpm_get_daa(handle); if (sessionDAA != NULL) { memset(sessionDAA, 0, sizeof(*sessionDAA)); if (handle == tpmData.stany.data.currentDAA) tpmData.stany.data.currentDAA = 0; tpm_invalidate_sessions(handle); } return TPM_SUCCESS; } return TPM_INVALID_RESOURCE; } ================================================ FILE: tpm/tpm_handles.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_handles.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_handles.h" #include "tpm_data.h" TPM_KEY_DATA *tpm_get_key_slot(TPM_KEY_HANDLE handle) { if (handle == TPM_INVALID_HANDLE) return NULL; handle &= 0x00ffffff; if (handle >= TPM_MAX_KEYS) return NULL; return &tpmData.permanent.data.keys[handle]; } TPM_SESSION_DATA *tpm_get_session_slot(TPM_HANDLE handle) { if (handle == TPM_INVALID_HANDLE) return NULL; handle &= 0x00ffffff; if (handle >= TPM_MAX_SESSIONS) return NULL; return &tpmData.stany.data.sessions[handle]; } TPM_DAA_SESSION_DATA *tpm_get_daa_slot(TPM_HANDLE handle) { if (handle == TPM_INVALID_HANDLE) return NULL; handle &= 0x00ffffff; if (handle >= TPM_MAX_SESSIONS_DAA) return NULL; return &tpmData.stany.data.sessionsDAA[handle]; } TPM_KEY_DATA *tpm_get_key(TPM_KEY_HANDLE handle) { /* handle reserved key handles */ switch (handle) { case TPM_KH_EK: case TPM_KH_OWNER: case TPM_KH_REVOKE: case TPM_KH_TRANSPORT: case TPM_KH_OPERATOR: case TPM_KH_ADMIN: return NULL; case TPM_KH_SRK: debug("SRK valid? %d", tpmData.permanent.data.srk.payload); return (tpmData.permanent.data.srk.payload) ? &tpmData.permanent.data.srk : NULL; } if (handle == TPM_INVALID_HANDLE || (handle >> 24) != TPM_RT_KEY) return NULL; handle &= 0x00ffffff; if (handle >= TPM_MAX_KEYS || !tpmData.permanent.data.keys[handle].payload) return NULL; return &tpmData.permanent.data.keys[handle]; } TPM_SESSION_DATA *tpm_get_auth(TPM_AUTHHANDLE handle) { if (handle == TPM_INVALID_HANDLE || (handle >> 24) != TPM_RT_AUTH) return NULL; handle &= 0x00ffffff; if (handle >= TPM_MAX_SESSIONS || (tpmData.stany.data.sessions[handle].type != TPM_ST_OIAP && tpmData.stany.data.sessions[handle].type != TPM_ST_OSAP && tpmData.stany.data.sessions[handle].type != TPM_ST_DSAP)) return NULL; return &tpmData.stany.data.sessions[handle]; } TPM_SESSION_DATA *tpm_get_transport(TPM_TRANSHANDLE handle) { if (handle == TPM_INVALID_HANDLE || (handle >> 24) != TPM_RT_TRANS) return NULL; handle &= 0x00ffffff; if (handle >= TPM_MAX_SESSIONS || tpmData.stany.data.sessions[handle].type != TPM_ST_TRANSPORT) return NULL; return &tpmData.stany.data.sessions[handle]; } TPM_COUNTER_VALUE *tpm_get_counter(TPM_COUNT_ID handle) { if ((handle == TPM_INVALID_HANDLE) || ((handle >> 24) != TPM_RT_COUNTER)) return NULL; handle &= 0x00ffffff; if ((handle >= TPM_MAX_COUNTERS) || !tpmData.permanent.data.counters[handle].valid) return NULL; return &tpmData.permanent.data.counters[handle]; } TPM_DAA_SESSION_DATA *tpm_get_daa(TPM_DAAHANDLE handle) { if ((handle == TPM_INVALID_HANDLE) || ((handle >> 24) != TPM_RT_DAA_TPM)) return NULL; handle &= 0x00ffffff; if ((handle >= TPM_MAX_SESSIONS_DAA) || (tpmData.stany.data.sessionsDAA[handle].type != TPM_ST_DAA)) return NULL; return &tpmData.stany.data.sessionsDAA[handle]; } ================================================ FILE: tpm/tpm_handles.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_handles.h 364 2010-02-11 10:24:45Z mast $ */ #ifndef _TPM_HANDLES_ #define _TPM_HANDLES_ #include "tpm_structures.h" /* * definition of an invalid handle */ #define TPM_INVALID_HANDLE 0xFFFFFFFF /* * macros to convert array indices to handles */ #define INDEX_TO_KEY_HANDLE(i) ((i) | (TPM_RT_KEY << 24)) #define INDEX_TO_AUTH_HANDLE(i) ((i) | (TPM_RT_AUTH << 24)) #define INDEX_TO_TRANS_HANDLE(i) ((i) | (TPM_RT_TRANS << 24)) #define INDEX_TO_COUNTER_HANDLE(i) ((i) | (TPM_RT_COUNTER << 24)) #define INDEX_TO_DAA_HANDLE(i) ((i) | (TPM_RT_DAA_TPM << 24)) /* * marco to convert handles to indices */ #define HANDLE_TO_INDEX(h) ((h) & 0x00FFFFFF) /* * macro to get the ressource type of a handle */ #define HANDLE_TO_RT(h) ((h) >> 24) /* * functions to get the dedicated data for a handle */ TPM_KEY_DATA *tpm_get_key_slot(TPM_KEY_HANDLE handle); TPM_SESSION_DATA *tpm_get_session_slot(TPM_HANDLE handle); TPM_DAA_SESSION_DATA *tpm_get_daa_slot(TPM_HANDLE handle); TPM_KEY_DATA *tpm_get_key(TPM_KEY_HANDLE handle); TPM_SESSION_DATA *tpm_get_auth(TPM_AUTHHANDLE handle); TPM_SESSION_DATA *tpm_get_transport(TPM_TRANSHANDLE handle); TPM_COUNTER_VALUE *tpm_get_counter(TPM_COUNT_ID handle); TPM_DAA_SESSION_DATA *tpm_get_daa(TPM_DAAHANDLE handle); TPM_NV_DATA_SENSITIVE *tpm_get_nvs(TPM_NV_INDEX index); #endif /* _TPM_HANDLES_ */ ================================================ FILE: tpm/tpm_identity.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * 2005-2008 Heiko Stamer * * 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_identity.c 468 2011-09-09 07:58:42Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "crypto/sha1.h" #include "crypto/rsa.h" #include "tpm_handles.h" #include "tpm_marshalling.h" #define LOCALITY tpmData.stany.flags.localityModifier /* * Identity Creation and Activation ([TPM_Part3], Section 15) */ TPM_RESULT TPM_MakeIdentity( TPM_ENCAUTH *identityAuth, TPM_CHOSENID_HASH *labelPrivCADigest, TPM_KEY *idKeyParams, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_KEY *idKey, UINT32 *identityBindingSize, BYTE **identityBinding ) { TPM_RESULT res; TPM_SESSION_DATA *ownerAuth_sessionData; TPM_SECRET A1; tpm_rsa_private_key_t tpm_signature_key; UINT32 key_length; TPM_STORE_ASYMKEY store; TPM_IDENTITY_CONTENTS idContents; UINT32 len; BYTE *buf, *ptr; info("TPM_MakeIdentity()"); /* 1. Validate the idKeyParams parameters for the key description */ if (idKeyParams->algorithmParms.encScheme != TPM_ES_NONE || idKeyParams->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) return TPM_BAD_KEY_PROPERTY; /* a. If the algorithm type is RSA the key length MUST be a minimum of 2048. * For interoperability the key length SHOULD be 2048 */ /* b. If the algorithm type is other than RSA the strength provided by the * key MUST be comparable to RSA 2048 */ /* c. If the TPM is not designed to create a key of the requested type, * return the error code TPM_BAD_KEY_PROPERTY */ switch (idKeyParams->algorithmParms.algorithmID) { case TPM_ALG_RSA: if (idKeyParams->algorithmParms.parmSize == 0 || idKeyParams->algorithmParms.parms.rsa.keyLength != 2048 || idKeyParams->algorithmParms.parms.rsa.numPrimes != 2 || idKeyParams->algorithmParms.parms.rsa.exponentSize != 0) return TPM_BAD_KEY_PROPERTY; break; default: return TPM_BAD_KEY_PROPERTY; } /* d. If TPM_PERMANENT_FLAGS->FIPS is TRUE then */ if (tpmData.permanent.flags.FIPS == TRUE) { /* i. If authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ if (idKeyParams->authDataUsage == TPM_AUTH_NEVER) return TPM_NOTFIPS; } /* 2. Use authHandle to verify that the Owner authorized all TPM_MakeIdentity * input parameters. */ if (auth2->authHandle != TPM_INVALID_HANDLE) { res = tpm_verify_auth(auth2, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; ownerAuth_sessionData = tpm_get_auth(auth2->authHandle); } else { res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; ownerAuth_sessionData = tpm_get_auth(auth1->authHandle); } /* 3. Use srkAuthHandle to verify that the SRK owner authorized all * TPM_MakeIdentity input parameters. */ if (auth2->authHandle != TPM_INVALID_HANDLE) { res = tpm_verify_auth(auth1, tpmData.permanent.data.srk.usageAuth, TPM_KH_SRK); if (res != TPM_SUCCESS) return res; } /* 4. Verify that idKeyParams->keyUsage is TPM_KEY_IDENTITY. If it is not, * return TPM_INVALID_KEYUSAGE */ if (idKeyParams->keyUsage != TPM_KEY_IDENTITY) return TPM_INVALID_KEYUSAGE; /* 5. Verify that idKeyParams->keyFlags->migratable is FALSE. If it is not, * return TPM_INVALID_KEYUSAGE */ if ((idKeyParams->keyFlags & TPM_KEY_FLAG_MIGRATABLE) == TPM_KEY_FLAG_MIGRATABLE) return TPM_INVALID_KEYUSAGE; /* 6. If ownerAuth indicates XOR encryption for the AuthData secrets */ if (ownerAuth_sessionData == NULL) return TPM_INVALID_AUTHHANDLE; if ((ownerAuth_sessionData->entityType & 0xFF00) == TPM_ET_XOR) { /* a. Create X1 the SHA-1 of the concatenation of (ownerAuth->sharedSecret * || authLastNonceEven) */ /* b. Create A1 by XOR X1 and identityAuth */ tpm_decrypt_auth_secret(*identityAuth, ownerAuth_sessionData->sharedSecret, &ownerAuth_sessionData->lastNonceEven, A1); } else { /* 7. Else */ /* a. Create A1 by decrypting identityAuth using the algorithm indicated * in the OSAP session */ /* b. Key is from ownerAuth->sharedSecret */ /* c. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ debug("TPM_MakeIdentity() does not support entityType=%.8x yet.", ownerAuth_sessionData->entityType); return TPM_FAIL; } /* 8. Set continueAuthSession and continueSRKSession to FALSE. */ auth2->continueAuthSession = FALSE, auth1->continueAuthSession = FALSE; /* 9. Determine the structure version */ /* a. If idKeyParms->tag is TPM_TAG_KEY12 */ if (idKeyParams->tag == TPM_TAG_KEY12) { /* i. Set V1 to 2 */ /* ii. Create idKey a TPM_KEY12 structure using idKeyParams as the * default values for the structure */ idKey->tag = TPM_TAG_KEY12; idKey->fill = 0x0000; idKey->keyUsage = TPM_KEY_IDENTITY; idKey->keyFlags = idKeyParams->keyFlags; idKey->authDataUsage = idKeyParams->authDataUsage; idKey->algorithmParms.algorithmID = idKeyParams->algorithmParms.algorithmID; idKey->algorithmParms.encScheme = idKeyParams->algorithmParms.encScheme; idKey->algorithmParms.sigScheme = idKeyParams->algorithmParms.sigScheme; idKey->algorithmParms.parmSize = idKeyParams->algorithmParms.parmSize; switch (idKeyParams->algorithmParms.algorithmID) { case TPM_ALG_RSA: idKey->algorithmParms.parms.rsa.keyLength = idKeyParams->algorithmParms.parms.rsa.keyLength; idKey->algorithmParms.parms.rsa.numPrimes = idKeyParams->algorithmParms.parms.rsa.numPrimes; idKey->algorithmParms.parms.rsa.exponentSize = idKeyParams->algorithmParms.parms.rsa.exponentSize; break; default: return TPM_BAD_KEY_PROPERTY; } idKey->PCRInfoSize = idKeyParams->PCRInfoSize; idKey->PCRInfo.tag = TPM_TAG_PCR_INFO_LONG; idKey->PCRInfo.localityAtCreation = idKeyParams->PCRInfo.localityAtCreation; idKey->PCRInfo.localityAtRelease = idKeyParams->PCRInfo.localityAtRelease; idKey->PCRInfo.creationPCRSelection = idKeyParams->PCRInfo.creationPCRSelection; idKey->PCRInfo.releasePCRSelection = idKeyParams->PCRInfo.releasePCRSelection; idKey->PCRInfo.digestAtCreation = idKeyParams->PCRInfo.digestAtCreation; idKey->PCRInfo.digestAtRelease = idKeyParams->PCRInfo.digestAtRelease; } else if (idKeyParams->tag == 0x0101) { /* b. If idKeyParms->ver is 1.1 */ /* i. Set V1 to 1 */ /* ii. Create idKey a TPM_KEY structure using idKeyParams as the * default values for the structure */ idKey->tag = 0x0101; idKey->fill = 0x0000; idKey->keyUsage = TPM_KEY_IDENTITY; idKey->keyFlags = idKeyParams->keyFlags; idKey->authDataUsage = idKeyParams->authDataUsage; idKey->algorithmParms.algorithmID = idKeyParams->algorithmParms.algorithmID; idKey->algorithmParms.encScheme = idKeyParams->algorithmParms.encScheme; idKey->algorithmParms.sigScheme = idKeyParams->algorithmParms.sigScheme; idKey->algorithmParms.parmSize = idKeyParams->algorithmParms.parmSize; switch (idKeyParams->algorithmParms.algorithmID) { case TPM_ALG_RSA: idKey->algorithmParms.parms.rsa.keyLength = idKeyParams->algorithmParms.parms.rsa.keyLength; idKey->algorithmParms.parms.rsa.numPrimes = idKeyParams->algorithmParms.parms.rsa.numPrimes; idKey->algorithmParms.parms.rsa.exponentSize = idKeyParams->algorithmParms.parms.rsa.exponentSize; break; default: return TPM_BAD_KEY_PROPERTY; } idKey->PCRInfoSize = idKeyParams->PCRInfoSize; idKey->PCRInfo.tag = 0x0000; idKey->PCRInfo.creationPCRSelection = idKeyParams->PCRInfo.creationPCRSelection; idKey->PCRInfo.digestAtRelease = idKeyParams->PCRInfo.digestAtRelease; idKey->PCRInfo.digestAtCreation = idKeyParams->PCRInfo.digestAtCreation; } else { debug("TPM_MakeIdentity(): unsupport this TPM_KEY structure."); return TPM_FAIL; } /* 10. Set the digestAtCreation values for pcrInfo */ if (idKey->PCRInfoSize > 0) { res = tpm_compute_pcr_digest(&idKey->PCRInfo.creationPCRSelection, &idKey->PCRInfo.digestAtCreation, NULL); if (res != TPM_SUCCESS) return res; /* a. For PCR_INFO_LONG include the locality of the current command */ if (idKey->PCRInfo.tag == TPM_TAG_PCR_INFO_LONG) idKey->PCRInfo.localityAtCreation = (1 << LOCALITY); } /* 11. Create an asymmetric key pair (identityPubKey and tpm_signature_key) * using a TPM-protected capability, in accordance with the algorithm * specified in idKeyParams */ key_length = idKeyParams->algorithmParms.parms.rsa.keyLength; if (tpm_rsa_generate_key(&tpm_signature_key, key_length)) { debug("TPM_MakeIdentity(): tpm_rsa_generate_key() failed."); return TPM_FAIL; } /* 12. Ensure that the AuthData information in A1 is properly stored in the * idKey as usageAuth. */ memcpy(store.usageAuth, A1, sizeof(TPM_SECRET)); /* 13. Attach identityPubKey and tpm_signature_key to idKey */ idKey->pubKey.keyLength = key_length >> 3; idKey->pubKey.key = tpm_malloc(idKey->pubKey.keyLength); if (idKey->pubKey.key == NULL) { tpm_rsa_release_private_key(&tpm_signature_key); return TPM_NOSPACE; } store.privKey.keyLength = key_length >> 4; store.privKey.key = tpm_malloc(store.privKey.keyLength); if (store.privKey.key == NULL) { tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_NOSPACE; } idKey->encDataSize = tpmData.permanent.data.srk.key.size >> 3; idKey->encData = tpm_malloc(idKey->encDataSize); if (idKey->encData == NULL) { tpm_free(store.privKey.key); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_NOSPACE; } tpm_rsa_export_modulus(&tpm_signature_key, idKey->pubKey.key, NULL); tpm_rsa_export_prime1(&tpm_signature_key, store.privKey.key, NULL); /* 14. Set idKey->migrationAuth to TPM_PERMANENT_DATA->tpmProof */ memcpy(store.migrationAuth, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_SECRET)); /* 15. Ensure that all TPM_PAYLOAD_TYPE structures identify this key as * TPM_PT_ASYM */ store.payload = TPM_PT_ASYM; /* compute the digest on all public data of this key */ if (tpm_compute_key_digest(idKey, &store.pubDataDigest)) { debug("TPM_MakeIdentity(): tpm_compute_key_digest() failed."); tpm_free(idKey->encData); tpm_free(store.privKey.key); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_FAIL; } /* 16. Encrypt the private portion of idKey using the SRK as the parent key */ if (tpm_encrypt_private_key(&tpmData.permanent.data.srk, &store, idKey->encData, &idKey->encDataSize)) { tpm_free(idKey->encData); tpm_free(store.privKey.key); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_ENCRYPT_ERROR; } tpm_free(store.privKey.key); /* 17. Create a TPM_IDENTITY_CONTENTS structure named idContents using * labelPrivCADigest and the information from idKey */ idContents.ver.major = 1, idContents.ver.minor = 1; /* MUST BE 1.1, (Spec) */ idContents.ver.revMajor = 0, idContents.ver.revMinor = 0; idContents.ordinal = TPM_ORD_MakeIdentity; memcpy(&idContents.labelPrivCADigest, labelPrivCADigest, sizeof(TPM_CHOSENID_HASH)); idContents.identityPubKey.algorithmParms.algorithmID = idKey->algorithmParms.algorithmID; idContents.identityPubKey.algorithmParms.encScheme = idKey->algorithmParms.encScheme; idContents.identityPubKey.algorithmParms.sigScheme = idKey->algorithmParms.sigScheme; idContents.identityPubKey.algorithmParms.parmSize = idKey->algorithmParms.parmSize; switch (idKey->algorithmParms.algorithmID) { case TPM_ALG_RSA: idContents.identityPubKey.algorithmParms.parms.rsa.keyLength = idKey->algorithmParms.parms.rsa.keyLength; idContents.identityPubKey.algorithmParms.parms.rsa.numPrimes = idKey->algorithmParms.parms.rsa.numPrimes; idContents.identityPubKey.algorithmParms.parms.rsa.exponentSize = idKey->algorithmParms.parms.rsa.exponentSize; break; default: tpm_free(idKey->encData); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_BAD_KEY_PROPERTY; } idContents.identityPubKey.pubKey.keyLength = key_length >> 3; idContents.identityPubKey.pubKey.key = tpm_malloc(idContents.identityPubKey.pubKey.keyLength); if (idContents.identityPubKey.pubKey.key == NULL) { tpm_free(idKey->encData); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_NOSPACE; } tpm_rsa_export_modulus(&tpm_signature_key, idContents.identityPubKey.pubKey.key, NULL); len = sizeof_TPM_IDENTITY_CONTENTS((idContents)); buf = ptr = tpm_malloc(len); if (buf == NULL) { tpm_free(idContents.identityPubKey.pubKey.key); tpm_free(idKey->encData); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_NOSPACE; } if (tpm_marshal_TPM_IDENTITY_CONTENTS(&ptr, &len, &idContents)) { debug("TPM_MakeIdentity(): tpm_marshal_TPM_IDENTITY_CONTENTS() failed."); tpm_free(buf); tpm_free(idContents.identityPubKey.pubKey.key); tpm_free(idKey->encData); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_FAIL; } /* 18. Sign idContents using tpm_signature_key and * TPM_SS_RSASSAPKCS1v15_SHA1. Store the result in identityBinding. */ *identityBindingSize = tpm_signature_key.size >> 3; *identityBinding = tpm_malloc(*identityBindingSize); if (*identityBinding == NULL) { tpm_free(buf); tpm_free(idContents.identityPubKey.pubKey.key); tpm_free(idKey->encData); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_NOSPACE; } if (tpm_rsa_sign(&tpm_signature_key, RSA_SSA_PKCS1_SHA1, buf, sizeof_TPM_IDENTITY_CONTENTS((idContents)), *identityBinding)) { debug("TPM_MakeIdentity(): tpm_rsa_sign() failed."); tpm_free(*identityBinding); tpm_free(buf); tpm_free(idContents.identityPubKey.pubKey.key); tpm_free(idKey->encData); tpm_free(idKey->pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_FAIL; } tpm_free(buf); tpm_free(idContents.identityPubKey.pubKey.key); tpm_rsa_release_private_key(&tpm_signature_key); return TPM_SUCCESS; } TPM_RESULT TPM_ActivateIdentity( TPM_KEY_HANDLE idKeyHandle, UINT32 blobSize, BYTE *blob, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_SYMMETRIC_KEY *symmetricKey ) { TPM_RESULT res; TPM_KEY_DATA *idKey = NULL; TPM_PUBKEY pubKey; TPM_DIGEST H1; BYTE *B1 = NULL; size_t sizeB1 = 0; UINT32 len; BYTE *ptr; BYTE B1__what = 0x00; TPM_EK_BLOB B1__ekBlob; TPM_ASYM_CA_CONTENTS B1__asymCaContents; TPM_SYMMETRIC_KEY *K1 = NULL; TPM_EK_BLOB_ACTIVATE A1; TPM_COMPOSITE_HASH C1; info("TPM_ActivateIdentity()"); /* 1. Using the authHandle field, validate the owner's AuthData to execute * the command and all of the incoming parameters. */ if (auth2->authHandle != TPM_INVALID_HANDLE) { res = tpm_verify_auth(auth2, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; } else { res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; } /* 2. Using the idKeyAuthHandle, validate the AuthData to execute command * and all of the incoming parameters */ idKey = tpm_get_key(idKeyHandle); if (idKey == NULL) return TPM_INVALID_KEYHANDLE; if (auth2->authHandle != TPM_INVALID_HANDLE) { if (idKey->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, idKey->usageAuth, idKeyHandle); if (res != TPM_SUCCESS) return res; } } /* 3. Validate that the idKey is the public key of a valid TPM identity by * checking that idKeyHandle->keyUsage is TPM_KEY_IDENTITY. * Return TPM_BAD_PARAMETER on mismatch */ if (idKey->keyUsage != TPM_KEY_IDENTITY) return TPM_BAD_PARAMETER; /* 4. Create H1 the digest of a TPM_PUBKEY derived from idKey */ pubKey.pubKey.keyLength = idKey->key.size >> 3; pubKey.pubKey.key = tpm_malloc(pubKey.pubKey.keyLength); if (pubKey.pubKey.key == NULL) return TPM_NOSPACE; tpm_rsa_export_modulus(&idKey->key, pubKey.pubKey.key, NULL); if (tpm_setup_key_parms(idKey, &pubKey.algorithmParms) != 0) { debug("TPM_ActivateIdentity(): tpm_setup_key_parms() failed."); tpm_free(pubKey.pubKey.key); return TPM_FAIL; } tpm_free(pubKey.algorithmParms.parms.rsa.exponent); pubKey.algorithmParms.parms.rsa.exponentSize = 0; pubKey.algorithmParms.parmSize = 12; if (tpm_compute_pubkey_digest(&pubKey, &H1)) { debug("TPM_ActivateIdentity(): tpm_compute_pubkey_digest() failed."); tpm_free(pubKey.pubKey.key); return TPM_FAIL; } /* 5. Decrypt blob creating B1 using PRIVEK as the decryption key */ B1 = tpm_malloc(blobSize); if (B1 == NULL) { tpm_free(pubKey.pubKey.key); return TPM_NOSPACE; } if (tpm_rsa_decrypt(&tpmData.permanent.data.endorsementKey, RSA_ES_OAEP_SHA1, blob, blobSize, B1, &sizeB1)) { tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_DECRYPT_ERROR; } /* 6. Determine the type and version of B1 */ if ((((UINT16)B1[0] << 8) | B1[1]) == TPM_TAG_EK_BLOB) { /* a. If B1->tag is TPM_TAG_EK_BLOB then */ /* i. B1 is a TPM_EK_BLOB */ ptr = B1; len = sizeB1; if (tpm_unmarshal_TPM_EK_BLOB(&ptr, &len, &B1__ekBlob)) { debug("TPM_ActivateIdentity(): tpm_unmarshal_TPM_EK_BLOB() failed."); tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_FAIL; } B1__what = 0x02; } else { /* b. Else */ /* i. B1 is a TPM_ASYM_CA_CONTENTS. As there is no tag for this * structure it is possible for the TPM to make a mistake here but * other sections of the structure undergo validation */ ptr = B1; len = sizeB1; if (tpm_unmarshal_TPM_ASYM_CA_CONTENTS(&ptr, &len, &B1__asymCaContents)) { debug("TPM_ActivateIdentity(): tpm_unmarshal_TPM_ASYM_CA_CONTENTS() failed."); tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_FAIL; } B1__what = 0x01; } /* 7. If B1 is a version 1.1 TPM_ASYM_CA_CONTENTS then */ if (B1__what == 0x01) { /* a. Compare H1 to B1->idDigest on mismatch return TPM_BAD_PARAMETER */ if (memcmp(H1.digest, B1__asymCaContents.idDigest.digest, sizeof(H1.digest))) { tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_BAD_PARAMETER; } /* b. Set K1 to B1->sessionKey */ K1 = &B1__asymCaContents.sessionKey; } /* 8. If B1 is a TPM_EK_BLOB then */ if (B1__what == 0x02) { /* a. Validate that B1->ekType is TPM_EK_TYPE_ACTIVATE, * return TPM_BAD_TYPE if not. */ if (B1__ekBlob.ekType != TPM_EK_TYPE_ACTIVATE) { tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_BAD_TYPE; } /* b. Assign A1 as a TPM_EK_BLOB_ACTIVATE structure from B1->blob */ ptr = B1__ekBlob.blob; len = B1__ekBlob.blobSize; if (tpm_unmarshal_TPM_EK_BLOB_ACTIVATE(&ptr, &len, &A1)) { debug("TPM_ActivateIdentity(): tpm_unmarshal_TPM_EK_BLOB_ACTIVATE() failed."); tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_FAIL; } /* c. Compare H1 to A1->idDigest on mismatch return TPM_BAD_PARAMETER */ if (memcmp(H1.digest, A1.idDigest.digest, sizeof(H1.digest))) { tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_BAD_PARAMETER; } /* d. If A1->pcrSelection is not NULL */ if (A1.pcrInfo.pcrSelection.sizeOfSelect > 0) { /* i. Compute a composite hash C1 using the PCR selection * A1->pcrSelection */ if (tpm_compute_pcr_digest(&A1.pcrInfo.pcrSelection, &C1, NULL) != TPM_SUCCESS) { debug("TPM_ActivateIdentity(): tpm_compute_pcr_digest() failed."); tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_FAIL; } /* ii. Compare C1 to A1->pcrInfo->digestAtRelease and return * TPM_WRONGPCRVAL on a mismatch */ if (memcmp(&C1, &A1.pcrInfo.digestAtRelease, sizeof(TPM_COMPOSITE_HASH))) { tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_WRONGPCRVAL; } /* iii. If A1->pcrInfo specifies a locality ensure that the * appropriate locality has been asserted, return TPM_BAD_LOCALITY * on error */ if (!(A1.pcrInfo.localityAtRelease & (1 << LOCALITY))) { tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_BAD_LOCALITY; } } /* e. Set K1 to A1->sessionKey */ K1 = &A1.sessionKey; } /* 9. Return K1 */ if (K1 != NULL) { symmetricKey->algId = K1->algId; symmetricKey->encScheme = K1->encScheme; symmetricKey->size = K1->size; memcpy(symmetricKey->data, K1->data, K1->size); } tpm_free(pubKey.pubKey.key); tpm_free(B1); return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_integrity.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_integrity.c 474 2011-12-20 10:27:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "crypto/sha1.h" #include "crypto/rsa.h" #include "tpm_handles.h" #include "tpm_marshalling.h" /* * Integrity Collection and Reporting ([TPM_Part3], Section 16) * This section deals with what commands have direct access to the PCR. */ #define PCR_ATTRIB tpmData.permanent.data.pcrAttrib #define PCR_VALUE tpmData.permanent.data.pcrValue #define LOCALITY tpmData.stany.flags.localityModifier TPM_RESULT TPM_Extend(TPM_PCRINDEX pcrNum, TPM_DIGEST *inDigest, TPM_PCRVALUE *outDigest) { tpm_sha1_ctx_t ctx; info("TPM_Extend()"); if (pcrNum >= TPM_NUM_PCR) return TPM_BADINDEX; if (!(PCR_ATTRIB[pcrNum].pcrExtendLocal & (1 << LOCALITY))) return TPM_BAD_LOCALITY; /* compute new PCR value as SHA-1(old PCR value || inDigest) */ tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, PCR_VALUE[pcrNum].digest, sizeof(PCR_VALUE[pcrNum].digest)); tpm_sha1_update(&ctx, inDigest->digest, sizeof(inDigest->digest)); tpm_sha1_final(&ctx, PCR_VALUE[pcrNum].digest); /* set output digest */ if (tpmData.permanent.flags.disable) { memset(outDigest->digest, 0, sizeof(*outDigest->digest)); } else { memcpy(outDigest, &PCR_VALUE[pcrNum], sizeof(TPM_PCRVALUE)); } return TPM_SUCCESS; } TPM_RESULT TPM_PCRRead(TPM_PCRINDEX pcrIndex, TPM_PCRVALUE *outDigest) { info("TPM_PCRRead()"); if (pcrIndex >= TPM_NUM_PCR) return TPM_BADINDEX; memcpy(outDigest, &PCR_VALUE[pcrIndex], sizeof(TPM_PCRVALUE)); return TPM_SUCCESS; } TPM_RESULT TPM_Quote(TPM_KEY_HANDLE keyHandle, TPM_NONCE *extrnalData, TPM_PCR_SELECTION *targetPCR, TPM_AUTH *auth1, TPM_PCR_COMPOSITE *pcrData, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_COMPOSITE_HASH hash; BYTE buf[48]; info("TPM_Quote()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } if (key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) return TPM_INAPPROPRIATE_SIG; if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY && key->keyUsage != TPM_KEY_IDENTITY) return TPM_INVALID_KEYUSAGE; /* compute composite hash */ res = tpm_compute_pcr_digest(targetPCR, &hash, pcrData); if (res != TPM_SUCCESS) return res; /* setup quote info and sign it */ memcpy(&buf[ 0], "\x01\x01\x00\x00QUOT", 8); memcpy(&buf[ 8], hash.digest, 20); memcpy(&buf[28], extrnalData->nonce, 20); *sigSize = key->key.size >> 3; *sig = tpm_malloc(*sigSize); if (*sig == NULL) return TPM_FAIL; if (tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1, buf, 48, *sig)) { tpm_free(*sig); return TPM_FAIL; } return TPM_SUCCESS; } TPM_RESULT TPM_PCR_Reset(TPM_PCR_SELECTION *pcrSelection) { int i; info("TPM_PCR_Reset()"); if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR) return TPM_INVALID_PCR_INFO; /* this command must be atomic, thus we first verify that all registers are resetable ... */ for (i = 0; i < pcrSelection->sizeOfSelect * 8; i++) { /* is PCR number i selected ? */ if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { if (!PCR_ATTRIB[i].pcrReset) return TPM_NOTRESETABLE; if (!(PCR_ATTRIB[i].pcrResetLocal & (1 << LOCALITY))) return TPM_NOTLOCAL; } } /* ... then we reset all registers at once */ for (i = 0; i < pcrSelection->sizeOfSelect * 8; i++) { /* is PCR number i selected ? */ if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { memset(PCR_VALUE[i].digest, 0, sizeof(PCR_VALUE[i].digest)); } } return TPM_SUCCESS; } TPM_RESULT tpm_compute_pcr_digest(TPM_PCR_SELECTION *pcrSelection, TPM_COMPOSITE_HASH *digest, TPM_PCR_COMPOSITE *composite) { int i,j; TPM_PCR_COMPOSITE comp; tpm_sha1_ctx_t ctx; UINT32 len; BYTE *buf, *ptr; info("tpm_compute_pcr_digest()"); /* create PCR composite */ if ((pcrSelection->sizeOfSelect * 8) > TPM_NUM_PCR || pcrSelection->sizeOfSelect == 0) return TPM_INVALID_PCR_INFO; for (i = 0, j = 0; i < pcrSelection->sizeOfSelect * 8; i++) { /* is PCR number i selected ? */ if (pcrSelection->pcrSelect[i >> 3] & (1 << (i & 7))) { memcpy(&comp.pcrValue[j++], &PCR_VALUE[i], sizeof(TPM_PCRVALUE)); } } memcpy(&comp.select, pcrSelection, sizeof(TPM_PCR_SELECTION)); comp.valueSize = j * sizeof(TPM_PCRVALUE); debug("comp.valueSize = %d", comp.valueSize); if (comp.valueSize > 0) { /* marshal composite and compute hash */ len = sizeof_TPM_PCR_COMPOSITE(comp); buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_PCR_COMPOSITE(&ptr, &len, &comp)) { tpm_free(buf); return TPM_FAIL; } tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, buf, sizeof_TPM_PCR_COMPOSITE(comp)); tpm_sha1_final(&ctx, digest->digest); tpm_free(buf); } else { memset(digest, 0, sizeof(TPM_COMPOSITE_HASH)); } /* copy composite if requested */ if (composite != NULL) memcpy(composite, &comp, sizeof(TPM_PCR_COMPOSITE)); return TPM_SUCCESS; } TPM_RESULT tpm_verify_pcr(TPM_KEY_DATA *key, BOOL atrelease, BOOL atcreation) { TPM_RESULT res; TPM_COMPOSITE_HASH digest; info("tpm_verify_pcr()"); if (atrelease) { res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &key->pcrInfo.digestAtRelease, sizeof(TPM_COMPOSITE_HASH))) return TPM_WRONGPCRVAL; if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG && !(key->pcrInfo.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; } if (atcreation) { res = tpm_compute_pcr_digest(&key->pcrInfo.creationPCRSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &key->pcrInfo.digestAtCreation, sizeof(TPM_COMPOSITE_HASH))) return TPM_WRONGPCRVAL; if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG && !(key->pcrInfo.localityAtCreation & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; } return TPM_SUCCESS; } TPM_RESULT TPM_Quote2(TPM_KEY_HANDLE keyHandle, TPM_NONCE *externalData, TPM_PCR_SELECTION *targetPCR, BOOL addVersion, TPM_AUTH *auth1, TPM_PCR_INFO_SHORT *pcrData, UINT32 *versionInfoSize, TPM_CAP_VERSION_INFO *versionInfo, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_COMPOSITE_HASH H1; TPM_QUOTE_INFO2 Q1; tpm_sha1_ctx_t ctx; TPM_DIGEST digest; UINT32 respSize, len, size; BYTE *resp, *ptr, *buf; info("TPM_Quote2()"); /* get key by keyHandle*/ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* 1. The TPM MUST validate the AuthData to use the key pointed * to by keyhandle */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } /* 2. Validate that keyHandle->sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ if ((key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && (key->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) return TPM_INAPPROPRIATE_SIG; /* 3. Validate that keyHandle->keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY, or TPM_KEY_LEGACY, if not return TPM_INVALID_KEYUSAGE */ if ((key->keyUsage != TPM_KEY_SIGNING) && (key->keyUsage != TPM_KEY_LEGACY) && (key->keyUsage != TPM_KEY_IDENTITY)) return TPM_INVALID_KEYUSAGE; /* 4. Validate targetPCR is a valid TPM_PCR_SELECTION structure, * on errors return TPM_INVALID_PCR_INFO */ if (targetPCR->sizeOfSelect > sizeof(targetPCR->pcrSelect)) return TPM_INVALID_PCR_INFO; /* 5. Create H1 a SHA-1 hash of a TPM_PCR_COMPOSITE using the * TPM_STCLEAR_DATA->PCR[] indicated by targetPCR->pcrSelect */ res = tpm_compute_pcr_digest(targetPCR, &H1, NULL); if (res != TPM_SUCCESS) return res; /* 6. Create S1 a TPM_PCR_INFO_SHORT */ /* a. Set S1->pcrSelection to targetPCR */ pcrData->pcrSelection.sizeOfSelect = targetPCR->sizeOfSelect; memcpy(pcrData->pcrSelection.pcrSelect, targetPCR->pcrSelect, targetPCR->sizeOfSelect); /* b. Set S1->localityAtRelease to TPM_STANY_DATA -> localityModifier */ pcrData->localityAtRelease = 1 << tpmData.stany.flags.localityModifier; /* c. Set S1->digestAtRelease to H1 */ memcpy(&pcrData->digestAtRelease, &H1, sizeof(TPM_COMPOSITE_HASH)); /* 7. Create Q1 a TPM_QUOTE_INFO2 structure */ Q1.tag = TPM_TAG_QUOTE_INFO2; /* a. Set Q1->fixed to "QUT2" */ Q1.fixed[0] = 'Q', Q1.fixed[1] = 'U', Q1.fixed[2] = 'T', Q1.fixed[3] = '2'; /* b. Set Q1->infoShort to S1 */ Q1.infoShort.pcrSelection.sizeOfSelect = pcrData->pcrSelection.sizeOfSelect; memcpy(Q1.infoShort.pcrSelection.pcrSelect, pcrData->pcrSelection.pcrSelect, pcrData->pcrSelection.sizeOfSelect); Q1.infoShort.localityAtRelease = pcrData->localityAtRelease; memcpy(Q1.infoShort.digestAtRelease.digest, pcrData->digestAtRelease.digest, sizeof(TPM_COMPOSITE_HASH)); /* c. Set Q1->externalData to externalData */ memcpy(&Q1.externalData, externalData, sizeof(TPM_NONCE)); size = len = sizeof_TPM_QUOTE_INFO2(Q1); buf = ptr = tpm_malloc(size); if (buf == NULL) return TPM_NOSPACE; if (tpm_marshal_TPM_QUOTE_INFO2(&ptr, &len, &Q1) || (len != 0)) { debug("TPM_Quote2(): tpm_marshal_TPM_QUOTE_INFO2() failed."); tpm_free(buf); return TPM_FAIL; } /* 8. If addVersion is TRUE */ if (addVersion == TRUE) { debug("TPM_Quote2(): addVersion == TRUE"); /* a. Concatenate to Q1 a TPM_CAP_VERSION_INFO structure */ res = TPM_GetCapability(TPM_CAP_VERSION_VAL, 0, NULL, &respSize, &resp); if (res != TPM_SUCCESS) { debug("TPM_Quote2(): cap_version_val() failed."); tpm_free(buf); return TPM_FAIL; } /* b. Set the output parameters for versionInfo */ ptr = resp; len = respSize; if (tpm_unmarshal_TPM_CAP_VERSION_INFO(&ptr, &len, versionInfo) || (len != 0)) { debug("TPM_Quote2(): tpm_unmarshal_TPM_CAP_VERSION_INFO() failed."); tpm_free(buf); return TPM_FAIL; } *versionInfoSize = respSize; } else { /* 9. Else */ debug("TPM_Quote2(): addVersion == FALSE"); /* a. Set versionInfoSize to 0 */ *versionInfoSize = 0; /* b. Return no bytes in versionInfo */ } /* 10. Sign a SHA-1 hash of Q1 using keyHandle as the signature key */ tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, buf, size); tpm_free(buf); if (addVersion == TRUE) { tpm_sha1_update(&ctx, resp, respSize); tpm_free(resp); } tpm_sha1_final(&ctx, digest.digest); /* 11. Return the signature in sig */ return tpm_sign(key, auth1, FALSE, digest.digest, sizeof(TPM_DIGEST), sig, sigSize); } ================================================ FILE: tpm/tpm_maintenance.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_maintenance.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_marshalling.h" #include "tpm_data.h" #include "crypto/sha1.h" /* * Maintenance Functions ([TPM_Part3], Section 12) */ static int tpm_setup_privkey(TPM_KEY_DATA *key, TPM_KEY *privkey) { size_t key_length; privkey->tag = TPM_TAG_KEY12; privkey->fill = 0; privkey->keyUsage = key->keyUsage; privkey->keyFlags = key->keyFlags; privkey->authDataUsage = key->authDataUsage; if (tpm_setup_key_parms(key, &privkey->algorithmParms) != 0) return -1; memcpy(&privkey->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO)); privkey->PCRInfoSize = sizeof_TPM_PCR_INFO(privkey->PCRInfo); privkey->encDataSize = 0; privkey->encData = NULL; key_length = key->key.size >> 3; privkey->pubKey.key = tpm_malloc(key_length); if (privkey->pubKey.key == NULL) { free_TPM_KEY((*privkey)); return -1; } tpm_rsa_export_modulus(&key->key, privkey->pubKey.key, &key_length); privkey->pubKey.keyLength = key_length; return 0; } TPM_RESULT TPM_CreateMaintenanceArchive(BOOL generateRandom, TPM_AUTH *auth1, UINT32 *randomSize, BYTE **random, UINT32 *archiveSize, BYTE **archive) { TPM_RESULT res; TPM_KEY key; TPM_DIGEST key_digest; BYTE *buf, *ptr; UINT32 len; size_t buf_len, p_len; info("TPM_CreateMaintenanceArchive()"); if (!tpmData.permanent.flags.allowMaintenance) return TPM_DISABLED_CMD; res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (!tpmData.permanent.data.manuMaintPub.valid) return TPM_KEYNOTFOUND; /* set up a TPM_KEY structure for the SRK */ if (tpm_setup_privkey(&tpmData.permanent.data.srk, &key) != 0) { debug("tpm_setup_privkey(SRK) failed"); return TPM_FAIL; } if (tpm_compute_key_digest(&key, &key_digest) != 0) { debug("tpm_compute_key_digest() failed"); free_TPM_KEY(key); return TPM_FAIL; } /* generate an OAEP encoding of the TPM_MIGRATE_ASYMKEY structure for the SRK: 0x00|seed|0x00-pad|0x01|TPM_MIGRATE_ASYMKEY */ debug("generating OAEP encoding"); buf_len = tpmData.permanent.data.manuMaintPub.key.size >> 3; buf = tpm_malloc(buf_len); if (buf == NULL) { free_TPM_KEY(key); return TPM_NOSPACE; } buf[0] = 0x00; tpm_rsa_export_prime1(&tpmData.permanent.data.srk.key, &buf[5], &p_len); ptr = &buf[1]; len = 4; tpm_marshal_UINT32(&ptr, &len, p_len); memmove(&buf[buf_len - (1 + 45 + p_len - 16)], &buf[5 + 16], p_len - 16); memset(&buf[5 + 16], 0, buf_len - 1 - 20 - 1 - 45 - p_len + 16); len = 1 + 45 + p_len - 16; ptr = &buf[buf_len - len]; tpm_marshal_BYTE(&ptr, &len, 0x01); tpm_marshal_TPM_PAYLOAD_TYPE(&ptr, &len, TPM_PT_MAINT); tpm_marshal_TPM_NONCE(&ptr, &len, &tpmData.permanent.data.tpmProof); tpm_marshal_TPM_DIGEST(&ptr, &len, &key_digest); tpm_marshal_UINT32(&ptr, &len, p_len - 16); tpm_rsa_mask_generation(&buf[1], SHA1_DIGEST_LENGTH, &buf[1 + SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH - 1); tpm_rsa_mask_generation(&buf[1 + SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH - 1, &buf[1], SHA1_DIGEST_LENGTH); /* XOR encrypt OAEP encoding */ debug("generateRandom = %d", generateRandom); if (generateRandom) { *randomSize = buf_len; *random = tpm_malloc(*randomSize); if (*random == NULL) { free_TPM_KEY(key); tpm_free(buf); return TPM_NOSPACE; } tpm_get_random_bytes(*random, *randomSize); for (len = 0; len < buf_len; len++) buf[len] ^= (*random)[len]; } else { *randomSize = 0; *random = NULL; tpm_rsa_mask_generation(tpmData.permanent.data.ownerAuth, SHA1_DIGEST_LENGTH, buf, buf_len); } /* RSA encrypt OAEP encoding */ if (tpm_rsa_encrypt(&tpmData.permanent.data.manuMaintPub.key, RSA_ES_PLAIN, buf, buf_len, buf, &buf_len) != 0) { debug("tpm_rsa_encrypt() failed"); free_TPM_KEY(key); tpm_free(buf); return TPM_FAIL; } key.encData = buf; key.encDataSize = buf_len; /* marshal response */ len = *archiveSize = sizeof_TPM_KEY(key); ptr = *archive = tpm_malloc(len); debug("archiveSize = %d, archive = %p", *archiveSize, *archive); if (ptr == NULL || tpm_marshal_TPM_KEY(&ptr, &len, &key)) { tpm_free(ptr); tpm_free(*random); free_TPM_KEY(key); return TPM_NOSPACE; } free_TPM_KEY(key); *archiveSize -= len; tpmData.permanent.flags.maintenanceDone = TRUE; return TPM_SUCCESS; } TPM_RESULT TPM_LoadMaintenanceArchive(UINT32 archiveSize, BYTE *archive, UINT32 sigSize, BYTE *sig, UINT32 randomSize, BYTE *random, TPM_AUTH *auth1) { TPM_RESULT res; TPM_KEY newsrk; TPM_DIGEST digest; tpm_sha1_ctx_t sha1; BYTE *buf, *ptr; UINT32 len; size_t buf_len; info("TPM_LoadMaintenanceArchive()"); /* verify authorization */ if (!tpmData.permanent.data.manuMaintPub.valid) return TPM_KEYNOTFOUND; if (!tpmData.permanent.flags.allowMaintenance) return TPM_DISABLED_CMD; res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* verify signature */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, archive, archiveSize); tpm_sha1_final(&sha1, digest.digest); if (sigSize != tpmData.permanent.data.manuMaintPub.key.size >> 3 || tpm_rsa_verify(&tpmData.permanent.data.manuMaintPub.key, RSA_SSA_PKCS1_SHA1, digest.digest, sizeof(digest.digest), sig) != 0) return TPM_BAD_SIGNATURE; /* unmarshal archive */ ptr = archive; len = archiveSize; if (tpm_unmarshal_TPM_KEY(&ptr, &len, &newsrk) != 0 || len != 0) return TPM_BAD_PARAMETER; /* decrypt private key */ buf_len = newsrk.encDataSize; buf = tpm_malloc(buf_len); if (buf == NULL) return TPM_NOSPACE; if (tpm_rsa_decrypt(&tpmData.permanent.data.srk.key, RSA_ES_PLAIN, newsrk.encData, newsrk.encDataSize, buf, &buf_len) || buf[0] != 0x00) { debug("tpm_rsa_decrypt() failed"); tpm_free(buf); return TPM_DECRYPT_ERROR; } if (randomSize > 0) { for (len = 0; len < buf_len; len++) buf[len] ^= random[len]; } else { tpm_rsa_mask_generation(tpmData.permanent.data.ownerAuth, SHA1_DIGEST_LENGTH, buf, buf_len); } tpm_rsa_mask_generation(&buf[1 + SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH - 1, &buf[1], SHA1_DIGEST_LENGTH); tpm_rsa_mask_generation(&buf[1], SHA1_DIGEST_LENGTH, &buf[1 + SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH - 1); /* validate new SRK */ if (newsrk.keyFlags & TPM_KEY_FLAG_MIGRATABLE || newsrk.keyUsage != TPM_KEY_STORAGE) return TPM_INVALID_KEYUSAGE; if (newsrk.algorithmParms.algorithmID != TPM_ALG_RSA || newsrk.algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || newsrk.algorithmParms.sigScheme != TPM_SS_NONE || newsrk.algorithmParms.parmSize == 0 || newsrk.algorithmParms.parms.rsa.keyLength != 2048 || newsrk.algorithmParms.parms.rsa.numPrimes != 2 || newsrk.algorithmParms.parms.rsa.exponentSize != 0 || newsrk.PCRInfoSize != 0) return TPM_BAD_KEY_PROPERTY; /* clear owner but keep ownerAuth */ memcpy(digest.digest, tpmData.permanent.data.ownerAuth, sizeof(TPM_SECRET)); tpm_owner_clear(); memcpy(tpmData.permanent.data.ownerAuth, digest.digest, sizeof(TPM_SECRET)); /* update tpmProof */ for (ptr = &buf[21]; *ptr == 0x00; ptr++); memcpy(&tpmData.permanent.data.tpmProof, &ptr[2], sizeof(TPM_NONCE)); ptr += 1 + 25; memmove(&buf[21], ptr, &buf[buf_len] - ptr); /* update SRK */ tpmData.permanent.data.srk.keyFlags = newsrk.keyFlags; tpmData.permanent.data.srk.keyFlags |= TPM_KEY_FLAG_PCR_IGNORE; tpmData.permanent.data.srk.keyFlags &= ~TPM_KEY_FLAG_HAS_PCR; tpmData.permanent.data.srk.keyUsage = newsrk.keyUsage; tpmData.permanent.data.srk.keyControl = TPM_KEY_CONTROL_OWNER_EVICT; tpmData.permanent.data.srk.encScheme = newsrk.algorithmParms.encScheme; tpmData.permanent.data.srk.sigScheme = newsrk.algorithmParms.sigScheme; tpmData.permanent.data.srk.authDataUsage = newsrk.authDataUsage; tpmData.permanent.data.srk.parentPCRStatus = FALSE; if (tpm_rsa_import_key(&tpmData.permanent.data.srk.key, RSA_MSB_FIRST, newsrk.pubKey.key, newsrk.pubKey.keyLength, newsrk.algorithmParms.parms.rsa.exponent, newsrk.algorithmParms.parms.rsa.exponentSize, &buf[5], NULL) != 0) { tpm_free(buf); debug("tpm_rsa_import_key() failed"); return TPM_FAIL; } /* enable SRK and mark TPM as owned */ tpmData.permanent.data.srk.payload = TPM_PT_ASYM; tpmData.permanent.flags.owned = TRUE; tpmData.permanent.flags.maintenanceDone = TRUE; tpm_free(buf); return TPM_SUCCESS; } TPM_RESULT TPM_KillMaintenanceFeature(TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_KillMaintenanceFeature()"); res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; tpmData.permanent.flags.allowMaintenance = FALSE; return TPM_SUCCESS; } TPM_RESULT TPM_LoadManuMaintPub(TPM_NONCE *antiReplay, TPM_PUBKEY *pubKey, TPM_DIGEST *checksum) { TPM_PUBKEY_DATA *key = &tpmData.permanent.data.manuMaintPub; info("TPM_LoadManuMaintPub()"); if (key->valid) return TPM_DISABLED_CMD; if (pubKey->algorithmParms.algorithmID != TPM_ALG_RSA || pubKey->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || pubKey->algorithmParms.sigScheme != TPM_SS_NONE || pubKey->algorithmParms.parms.rsa.keyLength < 2048) return TPM_BAD_KEY_PROPERTY; key->encScheme = pubKey->algorithmParms.encScheme; key->sigScheme = pubKey->algorithmParms.sigScheme; if (tpm_rsa_import_public_key(&key->key, RSA_MSB_FIRST, pubKey->pubKey.key, pubKey->pubKey.keyLength, pubKey->algorithmParms.parms.rsa.exponent, pubKey->algorithmParms.parms.rsa.exponentSize) != 0) return TPM_FAIL; if (tpm_compute_pubkey_checksum(antiReplay, pubKey, checksum) != 0) return TPM_FAIL; tpmData.permanent.data.manuMaintPub.valid = 1; return TPM_SUCCESS; } static int tpm_setup_pubkey(TPM_PUBKEY_DATA *key, TPM_PUBKEY *pubkey) { size_t key_length; key_length = key->key.size >> 3; pubkey->pubKey.key = tpm_malloc(key_length); if (pubkey->pubKey.key == NULL) return -1; tpm_rsa_export_public_modulus(&key->key, pubkey->pubKey.key, &key_length); pubkey->pubKey.keyLength = key_length; key_length = key->key.size >> 3; pubkey->algorithmParms.parms.rsa.exponent = tpm_malloc(key_length); if (pubkey->algorithmParms.parms.rsa.exponent == NULL) { tpm_free(pubkey->pubKey.key); return -1; } tpm_rsa_export_public_exponent(&key->key, pubkey->algorithmParms.parms.rsa.exponent, &key_length); pubkey->algorithmParms.parms.rsa.exponentSize = key_length; pubkey->algorithmParms.algorithmID = TPM_ALG_RSA; pubkey->algorithmParms.encScheme = key->encScheme; pubkey->algorithmParms.sigScheme = key->sigScheme; pubkey->algorithmParms.parms.rsa.keyLength = key->key.size; pubkey->algorithmParms.parms.rsa.numPrimes = 2; pubkey->algorithmParms.parmSize = sizeof_TPM_RSA_KEY_PARMS(pubkey->algorithmParms.parms.rsa); return 0; } TPM_RESULT TPM_ReadManuMaintPub(TPM_NONCE *antiReplay, TPM_DIGEST *checksum) { TPM_PUBKEY key; int res; info("TPM_ReadManuMaintPub()"); if (!tpmData.permanent.data.manuMaintPub.valid) return TPM_KEYNOTFOUND; if (tpm_setup_pubkey(&tpmData.permanent.data.manuMaintPub, &key) != 0) return TPM_FAIL; res = tpm_compute_pubkey_checksum(antiReplay, &key, checksum); free_TPM_PUBKEY(key); return (res == 0) ? TPM_SUCCESS : TPM_FAIL; } ================================================ FILE: tpm/tpm_management.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_management.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" /* * Administrative Functions ([TPM_Part3], Section 9) */ TPM_RESULT TPM_FieldUpgrade() { info("TPM_FieldUpgrade()"); /* nothing to do so far */ return TPM_SUCCESS; } TPM_RESULT TPM_SetRedirection(TPM_KEY_HANDLE keyHandle, TPM_REDIR_COMMAND redirCmd, UINT32 inputDataSize, BYTE *inputData, TPM_AUTH *auth1) { info("TPM_SetRedirection()"); /* this command is not supported by the TPM emulator */ return TPM_DISABLED_CMD; } TPM_RESULT TPM_ResetLockValue(TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_ResetLockValue"); if (tpmData.stclear.data.disableResetLock) return TPM_AUTHFAIL; res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) { tpmData.stclear.data.disableResetLock = TRUE; return res; } /* reset dictionary attack mitigation mechanism */ return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_marshalling.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * 2005-2008 Heiko Stamer * * 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_marshalling.c 372 2010-02-15 12:52:00Z mast $ */ #include "tpm_marshalling.h" #include "tpm_handles.h" #include "crypto/rsa.h" int tpm_marshal_UINT32_ARRAY(BYTE **ptr, UINT32 *length, UINT32 *v, UINT32 n) { UINT32 i; for (i = 0; i < n; i++) { if (tpm_marshal_UINT32(ptr, length, v[i])) return -1; } return 0; } int tpm_unmarshal_UINT32_ARRAY(BYTE **ptr, UINT32 *length, UINT32 *v, UINT32 n) { UINT32 i; for (i = 0; i < n; i++) { if (tpm_unmarshal_UINT32(ptr, length, &v[i])) return -1; } return 0; } int tpm_marshal_TPM_STRUCT_VER(BYTE **ptr, UINT32 *length, TPM_STRUCT_VER *v) { if (tpm_marshal_BYTE(ptr, length, v->major) || tpm_marshal_BYTE(ptr, length, v->minor) || tpm_marshal_BYTE(ptr, length, v->revMajor) || tpm_marshal_BYTE(ptr, length, v->revMinor)) return -1; return 0; } int tpm_unmarshal_TPM_STRUCT_VER(BYTE **ptr, UINT32 *length, TPM_STRUCT_VER *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->major) || tpm_unmarshal_BYTE(ptr, length, &v->minor) || tpm_unmarshal_BYTE(ptr, length, &v->revMajor) || tpm_unmarshal_BYTE(ptr, length, &v->revMinor)) return -1; return 0; } int tpm_marshal_TPM_VERSION(BYTE **ptr, UINT32 *length, TPM_VERSION *v) { if (tpm_marshal_BYTE(ptr, length, v->major) || tpm_marshal_BYTE(ptr, length, v->minor) || tpm_marshal_BYTE(ptr, length, v->revMajor) || tpm_marshal_BYTE(ptr, length, v->revMinor)) return -1; return 0; } int tpm_unmarshal_TPM_VERSION(BYTE **ptr, UINT32 *length, TPM_VERSION *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->major) || tpm_unmarshal_BYTE(ptr, length, &v->minor) || tpm_unmarshal_BYTE(ptr, length, &v->revMajor) || tpm_unmarshal_BYTE(ptr, length, &v->revMinor)) return -1; return 0; } int tpm_marshal_TPM_DIGEST(BYTE **ptr, UINT32 *length, TPM_DIGEST *v) { if (tpm_marshal_BYTE_ARRAY(ptr, length, v->digest, sizeof(v->digest))) return -1; return 0; } int tpm_unmarshal_TPM_DIGEST(BYTE **ptr, UINT32 *length, TPM_DIGEST *v) { if (tpm_unmarshal_BYTE_ARRAY(ptr, length, v->digest, sizeof(v->digest))) return -1; return 0; } int tpm_marshal_TPM_PCRVALUE_ARRAY(BYTE **ptr, UINT32 *length, TPM_PCRVALUE *v, UINT32 n) { UINT32 i; for (i = 0; i < n; i++) { if (tpm_marshal_TPM_PCRVALUE(ptr, length, &v[i])) return -1; } return 0; } int tpm_unmarshal_TPM_PCRVALUE_ARRAY(BYTE **ptr, UINT32 *length, TPM_PCRVALUE *v, UINT32 n) { UINT32 i; for (i = 0; i < n; i++) { if (tpm_unmarshal_TPM_PCRVALUE(ptr, length, &v[i])) return -1; } return 0; } int tpm_marshal_TPM_NONCE(BYTE **ptr, UINT32 *length, TPM_NONCE *v) { if (tpm_marshal_BYTE_ARRAY(ptr, length, v->nonce, sizeof(v->nonce))) return -1; return 0; } int tpm_unmarshal_TPM_NONCE(BYTE **ptr, UINT32 *length, TPM_NONCE *v) { if (tpm_unmarshal_BYTE_ARRAY(ptr, length, v->nonce, sizeof(v->nonce))) return -1; return 0; } int tpm_marshal_TPM_AUTHDATA(BYTE **ptr, UINT32 *length, TPM_AUTHDATA *v) { if (*length < sizeof(TPM_AUTHDATA)) return -1; memcpy(*ptr, v, sizeof(TPM_AUTHDATA)); *ptr += sizeof(TPM_AUTHDATA); *length -= sizeof(TPM_AUTHDATA); return 0; } int tpm_unmarshal_TPM_AUTHDATA(BYTE **ptr, UINT32 *length, TPM_AUTHDATA *v) { if (*length < sizeof(TPM_AUTHDATA)) return -1; memcpy(v, *ptr, sizeof(TPM_AUTHDATA)); *ptr += sizeof(TPM_AUTHDATA); *length -= sizeof(TPM_AUTHDATA); return 0; } int tpm_marshal_TPM_AUTH(BYTE **ptr, UINT32 *length, TPM_AUTH *v) { if (tpm_marshal_TPM_NONCE(ptr, length, &v->nonceEven) || tpm_marshal_BOOL(ptr, length, v->continueAuthSession) || tpm_marshal_TPM_AUTHDATA(ptr, length, &v->auth)) return -1; return 0; } int tpm_unmarshal_TPM_AUTH(BYTE **ptr, UINT32 *length, TPM_AUTH *v) { if (tpm_unmarshal_TPM_AUTHHANDLE(ptr, length, &v->authHandle) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->nonceOdd) || tpm_unmarshal_BOOL(ptr, length, &v->continueAuthSession) || tpm_unmarshal_TPM_AUTHDATA(ptr, length, &v->auth)) return -1; return 0; } int tpm_marshal_TPM_KEY_HANDLE_LIST(BYTE **ptr, UINT32 *length, TPM_KEY_HANDLE_LIST *v) { if (tpm_marshal_UINT16(ptr, length, v->loaded) || tpm_marshal_UINT32_ARRAY(ptr, length, v->handle, v->loaded)) return -1; return 0; } int tpm_marshal_TPM_CHANGEAUTH_VALIDATE(BYTE **ptr, UINT32 *length, TPM_CHANGEAUTH_VALIDATE *v) { if (tpm_marshal_TPM_SECRET(ptr, length, &v->newAuthSecret) || tpm_marshal_TPM_NONCE(ptr, length, &v->n1)) return -1; return 0; } int tpm_unmarshal_TPM_CHANGEAUTH_VALIDATE(BYTE **ptr, UINT32 *length, TPM_CHANGEAUTH_VALIDATE *v) { if (tpm_unmarshal_TPM_SECRET(ptr, length, &v->newAuthSecret) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->n1)) return -1; return 0; } int tpm_marshal_TPM_COUNTER_VALUE(BYTE **ptr, UINT32 *length, TPM_COUNTER_VALUE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BYTE_ARRAY(ptr, length, v->label, sizeof(v->label)) || tpm_marshal_TPM_ACTUAL_COUNT(ptr, length, v->counter)) return -1; return 0; } int tpm_unmarshal_TPM_COUNTER_VALUE(BYTE **ptr, UINT32 *length, TPM_COUNTER_VALUE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->label, sizeof(v->label)) || tpm_unmarshal_TPM_ACTUAL_COUNT(ptr, length, &v->counter)) return -1; return 0; } int tpm_marshal_TPM_PCR_SELECTION(BYTE **ptr, UINT32 *length, TPM_PCR_SELECTION *v) { if (tpm_marshal_UINT16(ptr, length, v->sizeOfSelect) || v->sizeOfSelect > sizeof(v->pcrSelect) || tpm_marshal_BYTE_ARRAY(ptr, length, v->pcrSelect, v->sizeOfSelect)) return -1; return 0; } int tpm_unmarshal_TPM_PCR_SELECTION(BYTE **ptr, UINT32 *length, TPM_PCR_SELECTION *v) { if (tpm_unmarshal_UINT16(ptr, length, &v->sizeOfSelect) || v->sizeOfSelect > sizeof(v->pcrSelect) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->pcrSelect, v->sizeOfSelect)) return -1; return 0; } int tpm_marshal_TPM_PCR_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_PCR_COMPOSITE *v) { if (tpm_marshal_TPM_PCR_SELECTION(ptr, length, &v->select) || tpm_marshal_UINT32(ptr, length, v->valueSize) || v->valueSize > sizeof(v->pcrValue) || tpm_marshal_TPM_PCRVALUE_ARRAY(ptr, length, v->pcrValue, v->valueSize / sizeof(TPM_PCRVALUE))) return -1; return 0; } int tpm_unmarshal_TPM_PCR_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_PCR_COMPOSITE *v) { if (tpm_unmarshal_TPM_PCR_SELECTION(ptr, length, &v->select) || tpm_unmarshal_UINT32(ptr, length, &v->valueSize) || v->valueSize > sizeof(v->pcrValue) || tpm_unmarshal_TPM_PCRVALUE_ARRAY(ptr, length, v->pcrValue, v->valueSize / sizeof(TPM_PCRVALUE))) return -1; return 0; } int tpm_marshal_TPM_PCR_INFO(BYTE **ptr, UINT32 *length, TPM_PCR_INFO *v) { if (v->tag == TPM_TAG_PCR_INFO_LONG) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_LOCALITY_SELECTION(ptr, length, v->localityAtCreation) || tpm_marshal_TPM_LOCALITY_SELECTION(ptr, length, v->localityAtRelease) || tpm_marshal_TPM_PCR_SELECTION(ptr, length, &v->creationPCRSelection) || tpm_marshal_TPM_PCR_SELECTION(ptr, length, &v->releasePCRSelection) || tpm_marshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtCreation) || tpm_marshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtRelease)) return -1; } else { if (tpm_marshal_TPM_PCR_SELECTION(ptr, length, &v->creationPCRSelection) || tpm_marshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtRelease) || tpm_marshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtCreation)) return -1; } return 0; } int tpm_unmarshal_TPM_PCR_INFO(BYTE **ptr, UINT32 *length, TPM_PCR_INFO *v) { if ((((UINT16)(*ptr)[0] << 8) | (*ptr)[1]) == TPM_TAG_PCR_INFO_LONG) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_LOCALITY_SELECTION(ptr, length, &v->localityAtCreation) || tpm_unmarshal_TPM_LOCALITY_SELECTION(ptr, length, &v->localityAtRelease) || tpm_unmarshal_TPM_PCR_SELECTION(ptr, length, &v->creationPCRSelection) || tpm_unmarshal_TPM_PCR_SELECTION(ptr, length, &v->releasePCRSelection) || tpm_unmarshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtCreation) || tpm_unmarshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtRelease)) return -1; } else { if (tpm_unmarshal_TPM_PCR_SELECTION(ptr, length, &v->creationPCRSelection) || tpm_unmarshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtRelease) || tpm_unmarshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtCreation)) return -1; memcpy(&v->releasePCRSelection, &v->creationPCRSelection, sizeof(TPM_PCR_SELECTION)); v->tag = 0x0000; v->localityAtCreation = 0; v->localityAtRelease = 0; } return 0; } int tpm_marshal_TPM_PCR_INFO_SHORT(BYTE **ptr, UINT32 *length, TPM_PCR_INFO_SHORT *v) { if (tpm_marshal_TPM_PCR_SELECTION(ptr, length, &v->pcrSelection) || tpm_marshal_TPM_LOCALITY_SELECTION(ptr, length, v->localityAtRelease) || tpm_marshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtRelease)) return -1; return 0; } int tpm_unmarshal_TPM_PCR_INFO_SHORT(BYTE **ptr, UINT32 *length, TPM_PCR_INFO_SHORT *v) { if (tpm_unmarshal_TPM_PCR_SELECTION(ptr, length, &v->pcrSelection) || tpm_unmarshal_TPM_LOCALITY_SELECTION(ptr, length, &v->localityAtRelease) || tpm_unmarshal_TPM_COMPOSITE_HASH(ptr, length, &v->digestAtRelease)) return -1; return 0; } int tpm_marshal_TPM_PCR_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_PCR_ATTRIBUTES *v) { if (tpm_marshal_BOOL(ptr, length, v->pcrReset) || tpm_marshal_TPM_LOCALITY_SELECTION(ptr, length, v->pcrResetLocal) || tpm_marshal_TPM_LOCALITY_SELECTION(ptr, length, v->pcrExtendLocal)) return -1; return 0; } int tpm_unmarshal_TPM_PCR_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_PCR_ATTRIBUTES *v) { if (tpm_unmarshal_BOOL(ptr, length, &v->pcrReset) || tpm_unmarshal_TPM_LOCALITY_SELECTION(ptr, length, &v->pcrResetLocal) || tpm_unmarshal_TPM_LOCALITY_SELECTION(ptr, length, &v->pcrExtendLocal)) return -1; return 0; } int tpm_marshal_TPM_STORED_DATA(BYTE **ptr, UINT32 *length, TPM_STORED_DATA *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_ENTITY_TYPE(ptr, length, v->et) || tpm_marshal_UINT32(ptr, length, v->sealInfoSize) || (v->sealInfoSize > 0 && tpm_marshal_TPM_PCR_INFO(ptr, length, &v->sealInfo)) || tpm_marshal_UINT32(ptr, length, v->encDataSize) || tpm_marshal_BLOB(ptr, length, v->encData, v->encDataSize)) return -1; return 0; } int tpm_unmarshal_TPM_STORED_DATA(BYTE **ptr, UINT32 *length, TPM_STORED_DATA *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_ENTITY_TYPE(ptr, length, &v->et) || tpm_unmarshal_UINT32(ptr, length, &v->sealInfoSize) || (v->sealInfoSize > 0 && tpm_unmarshal_TPM_PCR_INFO(ptr, length, &v->sealInfo)) || tpm_unmarshal_UINT32(ptr, length, &v->encDataSize) || tpm_unmarshal_BLOB(ptr, length, &v->encData, v->encDataSize)) return -1; return 0; } int tpm_marshal_TPM_SEALED_DATA(BYTE **ptr, UINT32 *length, TPM_SEALED_DATA *v) { if (tpm_marshal_TPM_PAYLOAD_TYPE(ptr, length, v->payload) || tpm_marshal_TPM_SECRET(ptr, length, &v->authData) || tpm_marshal_TPM_NONCE(ptr, length, &v->tpmProof) || tpm_marshal_TPM_DIGEST(ptr, length, &v->storedDigest) || tpm_marshal_UINT32(ptr, length, v->dataSize) || tpm_marshal_BLOB(ptr, length, v->data, v->dataSize)) return -1; return 0; } int tpm_unmarshal_TPM_SEALED_DATA(BYTE **ptr, UINT32 *length, TPM_SEALED_DATA *v) { if (tpm_unmarshal_TPM_PAYLOAD_TYPE(ptr, length, &v->payload) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->authData) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->tpmProof) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->storedDigest) || tpm_unmarshal_UINT32(ptr, length, &v->dataSize) || tpm_unmarshal_BLOB(ptr, length, &v->data, v->dataSize)) return -1; return 0; } int tpm_marshal_TPM_SYMMETRIC_KEY(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY *v) { if (tpm_marshal_TPM_ALGORITHM_ID(ptr, length, v->algId) || tpm_marshal_TPM_ENC_SCHEME(ptr, length, v->encScheme) || tpm_marshal_UINT16(ptr, length, v->size) || tpm_marshal_BLOB(ptr, length, v->data, v->size)) return -1; return 0; } int tpm_unmarshal_TPM_SYMMETRIC_KEY(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY *v) { if (tpm_unmarshal_TPM_ALGORITHM_ID(ptr, length, &v->algId) || tpm_unmarshal_TPM_ENC_SCHEME(ptr, length, &v->encScheme) || tpm_unmarshal_UINT16(ptr, length, &v->size) || tpm_unmarshal_BLOB(ptr, length, &v->data, v->size)) return -1; return 0; } int tpm_marshal_TPM_SYMMETRIC_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY_PARMS *v) { if (tpm_marshal_UINT32(ptr, length, v->keyLength) || tpm_marshal_UINT32(ptr, length, v->blockSize) || tpm_marshal_UINT32(ptr, length, v->ivSize) || tpm_marshal_BLOB(ptr, length, v->IV, v->ivSize)) return -1; return 0; } int tpm_unmarshal_TPM_SYMMETRIC_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY_PARMS *v) { if (tpm_unmarshal_UINT32(ptr, length, &v->keyLength) || tpm_unmarshal_UINT32(ptr, length, &v->blockSize) || tpm_unmarshal_UINT32(ptr, length, &v->ivSize) || tpm_unmarshal_BLOB(ptr, length, &v->IV, v->ivSize)) return -1; return 0; } int tpm_marshal_TPM_RSA_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_RSA_KEY_PARMS *v) { if (tpm_marshal_UINT32(ptr, length, v->keyLength) || tpm_marshal_UINT32(ptr, length, v->numPrimes) || tpm_marshal_UINT32(ptr, length, v->exponentSize) || tpm_marshal_BLOB(ptr, length, v->exponent, v->exponentSize)) return -1; return 0; } int tpm_unmarshal_TPM_RSA_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_RSA_KEY_PARMS *v) { if (tpm_unmarshal_UINT32(ptr, length, &v->keyLength) || tpm_unmarshal_UINT32(ptr, length, &v->numPrimes) || tpm_unmarshal_UINT32(ptr, length, &v->exponentSize) || tpm_unmarshal_BLOB(ptr, length, &v->exponent, v->exponentSize)) return -1; return 0; } int tpm_marshal_TPM_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_KEY_PARMS *v) { if (tpm_marshal_TPM_ALGORITHM_ID(ptr, length, v->algorithmID) || tpm_marshal_TPM_ENC_SCHEME(ptr, length, v->encScheme) || tpm_marshal_TPM_SIG_SCHEME(ptr, length, v->sigScheme) || tpm_marshal_UINT32(ptr, length, v->parmSize)) return -1; switch (v->algorithmID) { case TPM_ALG_RSA: if (tpm_marshal_TPM_RSA_KEY_PARMS(ptr, length, &v->parms.rsa)) return -1; break; case TPM_ALG_DES: case TPM_ALG_3DES: case TPM_ALG_AES192: case TPM_ALG_AES256: if (tpm_marshal_TPM_SYMMETRIC_KEY_PARMS(ptr, length, &v->parms.skp)) return -1; break; default: if (tpm_marshal_BLOB(ptr, length, v->parms.raw, v->parmSize)) return -1; } return 0; } int tpm_unmarshal_TPM_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_KEY_PARMS *v) { if (tpm_unmarshal_TPM_ALGORITHM_ID(ptr, length, &v->algorithmID) || tpm_unmarshal_TPM_ENC_SCHEME(ptr, length, &v->encScheme) || tpm_unmarshal_TPM_SIG_SCHEME(ptr, length, &v->sigScheme) || tpm_unmarshal_UINT32(ptr, length, &v->parmSize)) return -1; switch (v->algorithmID) { case TPM_ALG_RSA: if (tpm_unmarshal_TPM_RSA_KEY_PARMS(ptr, length, &v->parms.rsa)) return -1; break; case TPM_ALG_DES: case TPM_ALG_3DES: case TPM_ALG_AES192: case TPM_ALG_AES256: if (tpm_unmarshal_TPM_SYMMETRIC_KEY_PARMS(ptr, length, &v->parms.skp)) return -1; break; default: if (tpm_unmarshal_BLOB(ptr, length, &v->parms.raw, v->parmSize)) return -1; } return 0; } int tpm_marshal_TPM_STORE_PUBKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PUBKEY *v) { if (tpm_marshal_UINT32(ptr, length, v->keyLength) || tpm_marshal_BLOB(ptr, length, v->key, v->keyLength)) return -1; return 0; } int tpm_unmarshal_TPM_STORE_PUBKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PUBKEY *v) { if (tpm_unmarshal_UINT32(ptr, length, &v->keyLength) || tpm_unmarshal_BLOB(ptr, length, &v->key, v->keyLength)) return -1; return 0; } int tpm_marshal_TPM_KEY(BYTE **ptr, UINT32 *length, TPM_KEY *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_UINT16(ptr, length, v->fill) || tpm_marshal_TPM_KEY_USAGE(ptr, length, v->keyUsage) || tpm_marshal_TPM_KEY_FLAGS(ptr, length, v->keyFlags) || tpm_marshal_TPM_AUTH_DATA_USAGE(ptr, length, v->authDataUsage) || tpm_marshal_TPM_KEY_PARMS(ptr, length, &v->algorithmParms) || tpm_marshal_UINT32(ptr, length, v->PCRInfoSize) || (v->PCRInfoSize > 0 && tpm_marshal_TPM_PCR_INFO(ptr, length, &v->PCRInfo)) || tpm_marshal_TPM_STORE_PUBKEY(ptr, length, &v->pubKey) || tpm_marshal_UINT32(ptr, length, v->encDataSize) || tpm_marshal_BLOB(ptr, length, v->encData, v->encDataSize)) return -1; return 0; } int tpm_unmarshal_TPM_KEY(BYTE **ptr, UINT32 *length, TPM_KEY *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT16(ptr, length, &v->fill) || tpm_unmarshal_TPM_KEY_USAGE(ptr, length, &v->keyUsage) || tpm_unmarshal_TPM_KEY_FLAGS(ptr, length, &v->keyFlags) || tpm_unmarshal_TPM_AUTH_DATA_USAGE(ptr, length, &v->authDataUsage) || tpm_unmarshal_TPM_KEY_PARMS(ptr, length, &v->algorithmParms) || tpm_unmarshal_UINT32(ptr, length, &v->PCRInfoSize) || (v->PCRInfoSize > 0 && tpm_unmarshal_TPM_PCR_INFO(ptr, length, &v->PCRInfo)) || tpm_unmarshal_TPM_STORE_PUBKEY(ptr, length, &v->pubKey) || tpm_unmarshal_UINT32(ptr, length, &v->encDataSize) || tpm_unmarshal_BLOB(ptr, length, &v->encData, v->encDataSize)) return -1; return 0; } int tpm_marshal_TPM_PUBKEY(BYTE **ptr, UINT32 *length, TPM_PUBKEY *v) { if (tpm_marshal_TPM_KEY_PARMS(ptr, length, &v->algorithmParms) || tpm_marshal_TPM_STORE_PUBKEY(ptr, length, &v->pubKey)) return -1; return 0; } int tpm_unmarshal_TPM_PUBKEY(BYTE **ptr, UINT32 *length, TPM_PUBKEY *v) { if (tpm_unmarshal_TPM_KEY_PARMS(ptr, length, &v->algorithmParms) || tpm_unmarshal_TPM_STORE_PUBKEY(ptr, length, &v->pubKey)) return -1; return 0; } int tpm_marshal_TPM_STORE_PRIVKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PRIVKEY *v) { if (tpm_marshal_UINT32(ptr, length, v->keyLength) || tpm_marshal_BLOB(ptr, length, v->key, v->keyLength)) return -1; return 0; } int tpm_unmarshal_TPM_STORE_PRIVKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PRIVKEY *v) { if (tpm_unmarshal_UINT32(ptr, length, &v->keyLength) || tpm_unmarshal_BLOB(ptr, length, &v->key, v->keyLength)) return -1; return 0; } int tpm_marshal_TPM_STORE_ASYMKEY(BYTE **ptr, UINT32 *length, TPM_STORE_ASYMKEY *v) { if (tpm_marshal_TPM_PAYLOAD_TYPE(ptr, length, v->payload) || tpm_marshal_TPM_SECRET(ptr, length, &v->usageAuth) || tpm_marshal_TPM_SECRET(ptr, length, &v->migrationAuth) || tpm_marshal_TPM_DIGEST(ptr, length, &v->pubDataDigest) || tpm_marshal_TPM_STORE_PRIVKEY(ptr, length, &v->privKey)) return -1; return 0; } int tpm_unmarshal_TPM_STORE_ASYMKEY(BYTE **ptr, UINT32 *length, TPM_STORE_ASYMKEY *v) { if (tpm_unmarshal_TPM_PAYLOAD_TYPE(ptr, length, &v->payload) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->usageAuth) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->migrationAuth) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->pubDataDigest) || tpm_unmarshal_TPM_STORE_PRIVKEY(ptr, length, &v->privKey)) return -1; return 0; } int tpm_marshal_TPM_MIGRATIONKEYAUTH(BYTE **ptr, UINT32 *length, TPM_MIGRATIONKEYAUTH *v) { if (tpm_marshal_TPM_PUBKEY(ptr, length, &v->migrationKey) || tpm_marshal_TPM_MIGRATE_SCHEME(ptr, length, v->migrationScheme) || tpm_marshal_TPM_DIGEST(ptr, length, &v->digest)) return -1; return 0; } int tpm_unmarshal_TPM_MIGRATIONKEYAUTH(BYTE **ptr, UINT32 *length, TPM_MIGRATIONKEYAUTH *v) { if (tpm_unmarshal_TPM_PUBKEY(ptr, length, &v->migrationKey) || tpm_unmarshal_TPM_MIGRATE_SCHEME(ptr, length, &v->migrationScheme) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->digest)) return -1; return 0; } int tpm_marshal_TPM_CERTIFY_INFO(BYTE **ptr, UINT32 *length, TPM_CERTIFY_INFO *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BYTE(ptr, length, v->fill) || tpm_marshal_TPM_PAYLOAD_TYPE(ptr, length, v->payloadType) || tpm_marshal_TPM_KEY_USAGE(ptr, length, v->keyUsage) || tpm_marshal_TPM_KEY_FLAGS(ptr, length, v->keyFlags) || tpm_marshal_TPM_AUTH_DATA_USAGE(ptr, length, v->authDataUsage) || tpm_marshal_TPM_KEY_PARMS(ptr, length, &v->algorithmParms) || tpm_marshal_TPM_DIGEST(ptr, length, &v->pubkeyDigest) || tpm_marshal_TPM_NONCE(ptr, length, &v->data) || tpm_marshal_BOOL(ptr, length, v->parentPCRStatus) || tpm_marshal_UINT32(ptr, length, v->PCRInfoSize) || (v->PCRInfoSize > 0 && tpm_marshal_TPM_PCR_INFO(ptr, length, &v->PCRInfo)) || (v->tag == TPM_TAG_CERTIFY_INFO2 && tpm_marshal_UINT32(ptr, length, v->migrationAuthoritySize)) || (v->tag == TPM_TAG_CERTIFY_INFO2 && v->migrationAuthoritySize > 0 && tpm_marshal_BLOB(ptr, length, v->migrationAuthority, v->migrationAuthoritySize))) return -1; return 0; } int tpm_unmarshal_TPM_CERTIFY_INFO(BYTE **ptr, UINT32 *length, TPM_CERTIFY_INFO *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BYTE(ptr, length, &v->fill) || tpm_unmarshal_TPM_PAYLOAD_TYPE(ptr, length, &v->payloadType) || tpm_unmarshal_TPM_KEY_USAGE(ptr, length, &v->keyUsage) || tpm_unmarshal_TPM_KEY_FLAGS(ptr, length, &v->keyFlags) || tpm_unmarshal_TPM_AUTH_DATA_USAGE(ptr, length, &v->authDataUsage) || tpm_unmarshal_TPM_KEY_PARMS(ptr, length, &v->algorithmParms) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->pubkeyDigest) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->data) || tpm_unmarshal_BOOL(ptr, length, &v->parentPCRStatus) || tpm_unmarshal_UINT32(ptr, length, &v->PCRInfoSize) || (v->PCRInfoSize > 0 && tpm_unmarshal_TPM_PCR_INFO(ptr, length, &v->PCRInfo)) || (v->tag == TPM_TAG_CERTIFY_INFO2 && tpm_unmarshal_UINT32(ptr, length, &v->migrationAuthoritySize)) || (v->tag == TPM_TAG_CERTIFY_INFO2 && v->migrationAuthoritySize > 0 && tpm_unmarshal_BLOB(ptr, length, &v->migrationAuthority, v->migrationAuthoritySize))) return -1; return 0; } int tpm_marshal_TPM_IDENTITY_CONTENTS(BYTE **ptr, UINT32 *length, TPM_IDENTITY_CONTENTS *v) { if (tpm_marshal_TPM_STRUCT_VER(ptr, length, &v->ver) || tpm_marshal_UINT32(ptr, length, v->ordinal) || tpm_marshal_TPM_CHOSENID_HASH(ptr, length, &v->labelPrivCADigest) || tpm_marshal_TPM_PUBKEY(ptr, length, &v->identityPubKey)) return -1; return 0; } int tpm_unmarshal_TPM_IDENTITY_CONTENTS(BYTE **ptr, UINT32 *length, TPM_IDENTITY_CONTENTS *v) { if (tpm_unmarshal_TPM_STRUCT_VER(ptr, length, &v->ver) || tpm_unmarshal_UINT32(ptr, length, &v->ordinal) || tpm_unmarshal_TPM_CHOSENID_HASH(ptr, length, &v->labelPrivCADigest) || tpm_unmarshal_TPM_PUBKEY(ptr, length, &v->identityPubKey)) return -1; return 0; } int tpm_marshal_TPM_CURRENT_TICKS(BYTE **ptr, UINT32 *length, TPM_CURRENT_TICKS *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_UINT64(ptr, length, v->currentTicks) || tpm_marshal_UINT16(ptr, length, v->tickRate) || tpm_marshal_TPM_NONCE(ptr, length, &v->tickNonce)) return -1; return 0; } int tpm_unmarshal_TPM_CURRENT_TICKS(BYTE **ptr, UINT32 *length, TPM_CURRENT_TICKS *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT64(ptr, length, &v->currentTicks) || tpm_unmarshal_UINT16(ptr, length, &v->tickRate) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->tickNonce)) return -1; return 0; } int tpm_marshal_TPM_TRANSPORT_PUBLIC(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_PUBLIC *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_TRANSPORT_ATTRIBUTES(ptr, length, v->transAttributes) || tpm_marshal_TPM_ALGORITHM_ID(ptr, length, v->algID) || tpm_marshal_TPM_ENC_SCHEME(ptr, length, v->encScheme)) return -1; return 0; } int tpm_unmarshal_TPM_TRANSPORT_PUBLIC(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_PUBLIC *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_TRANSPORT_ATTRIBUTES(ptr, length, &v->transAttributes) || tpm_unmarshal_TPM_ALGORITHM_ID(ptr, length, &v->algID) || tpm_unmarshal_TPM_ENC_SCHEME(ptr, length, &v->encScheme)) return -1; return 0; } int tpm_marshal_TPM_TRANSPORT_INTERNAL(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_INTERNAL *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_AUTHDATA(ptr, length, &v->authData) || tpm_marshal_TPM_TRANSPORT_PUBLIC(ptr, length, &v->transPublic) || tpm_marshal_TPM_TRANSHANDLE(ptr, length, v->transHandle) || tpm_marshal_TPM_NONCE(ptr, length, &v->transNonceEven) || tpm_marshal_TPM_DIGEST(ptr, length, &v->transDigest)) return -1; return 0; } int tpm_unmarshal_TPM_TRANSPORT_INTERNAL(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_INTERNAL *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_AUTHDATA(ptr, length, &v->authData) || tpm_unmarshal_TPM_TRANSPORT_PUBLIC(ptr, length, &v->transPublic) || tpm_unmarshal_TPM_TRANSHANDLE(ptr, length, &v->transHandle) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->transNonceEven) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->transDigest)) return -1; return 0; } int tpm_marshal_TPM_CONTEXT_BLOB(BYTE **ptr, UINT32 *length, TPM_CONTEXT_BLOB *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_RESOURCE_TYPE(ptr, length, v->resourceType) || tpm_marshal_TPM_HANDLE(ptr, length, v->handle) || tpm_marshal_BYTE_ARRAY(ptr, length, v->label, sizeof(v->label)) || tpm_marshal_UINT32(ptr, length, v->contextCount) || tpm_marshal_TPM_DIGEST(ptr, length, &v->integrityDigest) || tpm_marshal_UINT32(ptr, length, v->additionalSize) || tpm_marshal_BLOB(ptr, length, v->additionalData, v->additionalSize) || tpm_marshal_UINT32(ptr, length, v->sensitiveSize) || tpm_marshal_BLOB(ptr, length, v->sensitiveData, v->sensitiveSize)) return -1; return 0; } int tpm_unmarshal_TPM_CONTEXT_BLOB(BYTE **ptr, UINT32 *length, TPM_CONTEXT_BLOB *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_RESOURCE_TYPE(ptr, length, &v->resourceType) || tpm_unmarshal_TPM_HANDLE(ptr, length, &v->handle) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->label, sizeof(v->label)) || tpm_unmarshal_UINT32(ptr, length, &v->contextCount) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->integrityDigest) || tpm_unmarshal_UINT32(ptr, length, &v->additionalSize) || tpm_unmarshal_BLOB(ptr, length, &v->additionalData, v->additionalSize) || tpm_unmarshal_UINT32(ptr, length, &v->sensitiveSize) || tpm_unmarshal_BLOB(ptr, length, &v->sensitiveData, v->sensitiveSize)) return -1; return 0; } int tpm_marshal_TPM_CONTEXT_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_CONTEXT_SENSITIVE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_NONCE(ptr, length, &v->contextNonce) || tpm_marshal_UINT32(ptr, length, v->internalSize) || tpm_marshal_TPM_RESOURCE_TYPE(ptr, length, v->resourceType)) return -1; switch (v->resourceType) { case TPM_RT_KEY: if (tpm_marshal_TPM_KEY_DATA(ptr, length, &v->internalData.key)) return -1; break; case TPM_RT_AUTH: case TPM_RT_TRANS: if (tpm_marshal_TPM_SESSION_DATA(ptr, length, &v->internalData.session)) return -1; break; case TPM_RT_DAA_TPM: if (tpm_marshal_TPM_DAA_SESSION_DATA(ptr, length, &v->internalData.sessionDAA)) return -1; break; default: return -1; } return 0; } int tpm_unmarshal_TPM_CONTEXT_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_CONTEXT_SENSITIVE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->contextNonce) || tpm_unmarshal_UINT32(ptr, length, &v->internalSize) || tpm_unmarshal_TPM_RESOURCE_TYPE(ptr, length, &v->resourceType)) return -1; switch (v->resourceType) { case TPM_RT_KEY: if (tpm_unmarshal_TPM_KEY_DATA(ptr, length, &v->internalData.key)) return -1; break; case TPM_RT_AUTH: case TPM_RT_TRANS: if (tpm_unmarshal_TPM_SESSION_DATA(ptr, length, &v->internalData.session)) return -1; break; case TPM_RT_DAA_TPM: if (tpm_unmarshal_TPM_DAA_SESSION_DATA(ptr, length, &v->internalData.sessionDAA)) return -1; break; default: return -1; } return 0; } int tpm_marshal_TPM_DAA_BLOB(BYTE **ptr, UINT32 *length, TPM_DAA_BLOB *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_RESOURCE_TYPE(ptr, length, v->resourceType) || tpm_marshal_BYTE_ARRAY(ptr, length, v->label, sizeof(v->label)) || tpm_marshal_TPM_DIGEST(ptr, length, &v->blobIntegrity) || tpm_marshal_UINT32(ptr, length, v->additionalSize) || tpm_marshal_BLOB(ptr, length, v->additionalData, v->additionalSize) || tpm_marshal_UINT32(ptr, length, v->sensitiveSize) || tpm_marshal_BLOB(ptr, length, v->sensitiveData, v->sensitiveSize)) return -1; return 0; } int tpm_unmarshal_TPM_DAA_BLOB(BYTE **ptr, UINT32 *length, TPM_DAA_BLOB *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_RESOURCE_TYPE(ptr, length, &v->resourceType) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->label, sizeof(v->label)) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->blobIntegrity) || tpm_unmarshal_UINT32(ptr, length, &v->additionalSize) || tpm_unmarshal_BLOB(ptr, length, &v->additionalData, v->additionalSize) || tpm_unmarshal_UINT32(ptr, length, &v->sensitiveSize) || tpm_unmarshal_BLOB(ptr, length, &v->sensitiveData, v->sensitiveSize)) return -1; return 0; } int tpm_marshal_TPM_DAA_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DAA_SENSITIVE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_UINT32(ptr, length, v->internalSize) || tpm_marshal_BYTE_ARRAY(ptr, length, v->internalData, v->internalSize)) return -1; return 0; } int tpm_unmarshal_TPM_DAA_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DAA_SENSITIVE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT32(ptr, length, &v->internalSize) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->internalData, v->internalSize)) return -1; return 0; } int tpm_marshal_TPM_DAA_ISSUER(BYTE **ptr, UINT32 *length, TPM_DAA_ISSUER *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_R0) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_R1) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_S0) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_S1) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_n) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_gamma) || tpm_marshal_BYTE_ARRAY(ptr, length, v->DAA_generic_q, sizeof(v->DAA_generic_q))) return -1; return 0; } int tpm_unmarshal_TPM_DAA_ISSUER(BYTE **ptr, UINT32 *length, TPM_DAA_ISSUER *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_R0) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_R1) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_S0) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_S1) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_n) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_gamma) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->DAA_generic_q, sizeof(v->DAA_generic_q))) return -1; return 0; } int tpm_marshal_TPM_DAA_TPM(BYTE **ptr, UINT32 *length, TPM_DAA_TPM *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digestIssuer) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_v0) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_v1) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_rekey) || tpm_marshal_UINT32(ptr, length, v->DAA_count)) return -1; return 0; } int tpm_unmarshal_TPM_DAA_TPM(BYTE **ptr, UINT32 *length, TPM_DAA_TPM *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digestIssuer) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_v0) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_v1) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_rekey) || tpm_unmarshal_UINT32(ptr, length, &v->DAA_count)) return -1; return 0; } int tpm_marshal_TPM_DAA_CONTEXT(BYTE **ptr, UINT32 *length, TPM_DAA_CONTEXT *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digestContext) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest) || tpm_marshal_TPM_NONCE(ptr, length, &v->DAA_contextSeed) || tpm_marshal_BYTE_ARRAY(ptr, length, v->DAA_scratch, sizeof(v->DAA_scratch)) || tpm_marshal_BYTE(ptr, length, v->DAA_stage)) return -1; return 0; } int tpm_unmarshal_TPM_DAA_CONTEXT(BYTE **ptr, UINT32 *length, TPM_DAA_CONTEXT *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digestContext) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->DAA_contextSeed) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->DAA_scratch, sizeof(v->DAA_scratch)) || tpm_unmarshal_BYTE(ptr, length, &v->DAA_stage)) return -1; return 0; } int tpm_marshal_TPM_DAA_JOINDATA(BYTE **ptr, UINT32 *length, TPM_DAA_JOINDATA *v) { if (tpm_marshal_BYTE_ARRAY(ptr, length, v->DAA_join_u0, sizeof(v->DAA_join_u0)) || tpm_marshal_BYTE_ARRAY(ptr, length, v->DAA_join_u1, sizeof(v->DAA_join_u1)) || tpm_marshal_TPM_DIGEST(ptr, length, &v->DAA_digest_n0)) return -1; return 0; } int tpm_unmarshal_TPM_DAA_JOINDATA(BYTE **ptr, UINT32 *length, TPM_DAA_JOINDATA *v) { if (tpm_unmarshal_BYTE_ARRAY(ptr, length, v->DAA_join_u0, sizeof(v->DAA_join_u0)) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->DAA_join_u1, sizeof(v->DAA_join_u1)) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->DAA_digest_n0)) return -1; return 0; } int tpm_marshal_TPM_DAA_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_DAA_SESSION_DATA *v) { if (tpm_marshal_BYTE(ptr, length, v->type) || tpm_marshal_TPM_DAA_ISSUER(ptr, length, &v->DAA_issuerSettings) || tpm_marshal_TPM_DAA_TPM(ptr, length, &v->DAA_tpmSpecific) || tpm_marshal_TPM_DAA_CONTEXT(ptr, length, &v->DAA_session) || tpm_marshal_TPM_DAA_JOINDATA(ptr, length, &v->DAA_joinSession) || tpm_marshal_TPM_HANDLE(ptr, length, v->handle)) return -1; return 0; } int tpm_unmarshal_TPM_DAA_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_DAA_SESSION_DATA *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->type) || tpm_unmarshal_TPM_DAA_ISSUER(ptr, length, &v->DAA_issuerSettings) || tpm_unmarshal_TPM_DAA_TPM(ptr, length, &v->DAA_tpmSpecific) || tpm_unmarshal_TPM_DAA_CONTEXT(ptr, length, &v->DAA_session) || tpm_unmarshal_TPM_DAA_JOINDATA(ptr, length, &v->DAA_joinSession) || tpm_unmarshal_TPM_HANDLE(ptr, length, &v->handle)) return -1; return 0; } int tpm_marshal_TPM_MSA_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_MSA_COMPOSITE *v) { UINT32 i; if (tpm_marshal_UINT32(ptr, length, v->MSAlist)) return -1; for (i = 0; i < v->MSAlist; i++) { if (tpm_marshal_TPM_DIGEST(ptr, length, &v->migAuthDigest[i])) return -1; } return 0; } int tpm_unmarshal_TPM_MSA_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_MSA_COMPOSITE *v) { UINT32 i; if (tpm_unmarshal_UINT32(ptr, length, &v->MSAlist)) return -1; if (v->MSAlist > MAX_MSA_COMPOSITE_ENTRIES) return -1; for (i = 0; i < v->MSAlist; i++) { if (tpm_unmarshal_TPM_DIGEST(ptr, length, &v->migAuthDigest[i])) return -1; } return 0; } int tpm_marshal_TPM_CMK_AUTH(BYTE **ptr, UINT32 *length, TPM_CMK_AUTH *v) { if (tpm_marshal_TPM_DIGEST(ptr, length, &v->migrationAuthorityDigest) || tpm_marshal_TPM_DIGEST(ptr, length, &v->destinationKeyDigest) || tpm_marshal_TPM_DIGEST(ptr, length, &v->sourceKeyDigest)) return -1; return 0; } int tpm_unmarshal_TPM_CMK_AUTH(BYTE **ptr, UINT32 *length, TPM_CMK_AUTH *v) { if (tpm_unmarshal_TPM_DIGEST(ptr, length, &v->migrationAuthorityDigest) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->destinationKeyDigest) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->sourceKeyDigest)) return -1; return 0; } int tpm_marshal_TPM_SELECT_SIZE(BYTE **ptr, UINT32 *length, TPM_SELECT_SIZE *v) { if (tpm_marshal_BYTE(ptr, length, v->major) || tpm_marshal_BYTE(ptr, length, v->minor) || tpm_marshal_UINT16(ptr, length, v->reqSize)) return -1; return 0; } int tpm_unmarshal_TPM_SELECT_SIZE(BYTE **ptr, UINT32 *length, TPM_SELECT_SIZE *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->major) || tpm_unmarshal_BYTE(ptr, length, &v->minor) || tpm_unmarshal_UINT16(ptr, length, &v->reqSize)) return -1; return 0; } int tpm_marshal_TPM_CAP_VERSION_INFO(BYTE **ptr, UINT32 *length, TPM_CAP_VERSION_INFO *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_VERSION(ptr, length, &v->version) || tpm_marshal_UINT16(ptr, length, v->specLevel) || tpm_marshal_BYTE(ptr, length, v->errataRev) || tpm_marshal_BYTE(ptr, length, v->tpmVendorID[0]) || tpm_marshal_BYTE(ptr, length, v->tpmVendorID[1]) || tpm_marshal_BYTE(ptr, length, v->tpmVendorID[2]) || tpm_marshal_BYTE(ptr, length, v->tpmVendorID[3]) || tpm_marshal_UINT16(ptr, length, v->vendorSpecificSize) || tpm_marshal_BLOB(ptr, length, v->vendorSpecific, v->vendorSpecificSize)) return -1; return 0; } int tpm_unmarshal_TPM_CAP_VERSION_INFO(BYTE **ptr, UINT32 *length, TPM_CAP_VERSION_INFO *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_VERSION(ptr, length, &v->version) || tpm_unmarshal_UINT16(ptr, length, &v->specLevel) || tpm_unmarshal_BYTE(ptr, length, &v->errataRev) || tpm_unmarshal_BYTE(ptr, length, &v->tpmVendorID[0]) || tpm_unmarshal_BYTE(ptr, length, &v->tpmVendorID[1]) || tpm_unmarshal_BYTE(ptr, length, &v->tpmVendorID[2]) || tpm_unmarshal_BYTE(ptr, length, &v->tpmVendorID[3]) || tpm_unmarshal_UINT16(ptr, length, &v->vendorSpecificSize) || tpm_unmarshal_BLOB(ptr, length, &v->vendorSpecific, v->vendorSpecificSize)) return -1; return 0; } int tpm_marshal_TPM_ASYM_CA_CONTENTS(BYTE **ptr, UINT32 *length, TPM_ASYM_CA_CONTENTS *v) { if (tpm_marshal_TPM_SYMMETRIC_KEY(ptr, length, &v->sessionKey) || tpm_marshal_TPM_DIGEST(ptr, length, &v->idDigest)) return -1; return 0; } int tpm_unmarshal_TPM_ASYM_CA_CONTENTS(BYTE **ptr, UINT32 *length, TPM_ASYM_CA_CONTENTS *v) { if (tpm_unmarshal_TPM_SYMMETRIC_KEY(ptr, length, &v->sessionKey) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->idDigest)) return -1; return 0; } int tpm_marshal_TPM_QUOTE_INFO2(BYTE **ptr, UINT32 *length, TPM_QUOTE_INFO2 *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BYTE(ptr, length, v->fixed[0]) || tpm_marshal_BYTE(ptr, length, v->fixed[1]) || tpm_marshal_BYTE(ptr, length, v->fixed[2]) || tpm_marshal_BYTE(ptr, length, v->fixed[3]) || tpm_marshal_TPM_NONCE(ptr, length, &v->externalData) || tpm_marshal_TPM_PCR_INFO_SHORT(ptr, length, &v->infoShort)) return -1; return 0; } int tpm_unmarshal_TPM_QUOTE_INFO2(BYTE **ptr, UINT32 *length, TPM_QUOTE_INFO2 *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BYTE(ptr, length, &v->fixed[0]) || tpm_unmarshal_BYTE(ptr, length, &v->fixed[1]) || tpm_unmarshal_BYTE(ptr, length, &v->fixed[2]) || tpm_unmarshal_BYTE(ptr, length, &v->fixed[3]) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->externalData) || tpm_unmarshal_TPM_PCR_INFO_SHORT(ptr, length, &v->infoShort)) return -1; return 0; } int tpm_marshal_TPM_EK_BLOB(BYTE **ptr, UINT32 *length, TPM_EK_BLOB *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_EK_TYPE(ptr, length, v->ekType) || tpm_marshal_UINT32(ptr, length, v->blobSize) || tpm_marshal_BLOB(ptr, length, v->blob, v->blobSize)) return -1; return 0; } int tpm_unmarshal_TPM_EK_BLOB(BYTE **ptr, UINT32 *length, TPM_EK_BLOB *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_EK_TYPE(ptr, length, &v->ekType) || tpm_unmarshal_UINT32(ptr, length, &v->blobSize) || tpm_unmarshal_BLOB(ptr, length, &v->blob, v->blobSize)) return -1; return 0; } int tpm_marshal_TPM_EK_BLOB_ACTIVATE(BYTE **ptr, UINT32 *length, TPM_EK_BLOB_ACTIVATE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_SYMMETRIC_KEY(ptr, length, &v->sessionKey) || tpm_marshal_TPM_DIGEST(ptr, length, &v->idDigest) || tpm_marshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfo)) return -1; return 0; } int tpm_unmarshal_TPM_EK_BLOB_ACTIVATE(BYTE **ptr, UINT32 *length, TPM_EK_BLOB_ACTIVATE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_SYMMETRIC_KEY(ptr, length, &v->sessionKey) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->idDigest) || tpm_unmarshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfo)) return -1; return 0; } int tpm_marshal_TPM_NV_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_NV_ATTRIBUTES *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_UINT32(ptr, length, v->attributes)) return -1; return 0; } int tpm_unmarshal_TPM_NV_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_NV_ATTRIBUTES *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT32(ptr, length, &v->attributes)) return -1; return 0; } int tpm_marshal_TPM_NV_DATA_PUBLIC(BYTE **ptr, UINT32 *length, TPM_NV_DATA_PUBLIC *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_NV_INDEX(ptr, length, v->nvIndex) || tpm_marshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfoRead) || tpm_marshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfoWrite) || tpm_marshal_TPM_NV_ATTRIBUTES(ptr, length, &v->permission) || tpm_marshal_BOOL(ptr, length, v->bReadSTClear) || tpm_marshal_BOOL(ptr, length, v->bWriteSTClear) || tpm_marshal_BOOL(ptr, length, v->bWriteDefine) || tpm_marshal_UINT32(ptr, length, v->dataSize)) return -1; return 0; } int tpm_unmarshal_TPM_NV_DATA_PUBLIC(BYTE **ptr, UINT32 *length, TPM_NV_DATA_PUBLIC *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_NV_INDEX(ptr, length, &v->nvIndex) || tpm_unmarshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfoRead) || tpm_unmarshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfoWrite) || tpm_unmarshal_TPM_NV_ATTRIBUTES(ptr, length, &v->permission) || tpm_unmarshal_BOOL(ptr, length, &v->bReadSTClear) || tpm_unmarshal_BOOL(ptr, length, &v->bWriteSTClear) || tpm_unmarshal_BOOL(ptr, length, &v->bWriteDefine) || tpm_unmarshal_UINT32(ptr, length, &v->dataSize)) return -1; return 0; } int tpm_marshal_TPM_NV_DATA_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_NV_DATA_SENSITIVE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_NV_DATA_PUBLIC(ptr, length, &v->pubInfo) || tpm_marshal_TPM_AUTHDATA(ptr, length, &v->authValue) || tpm_marshal_UINT32(ptr, length, v->dataIndex)) return -1; return 0; } int tpm_unmarshal_TPM_NV_DATA_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_NV_DATA_SENSITIVE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_NV_DATA_PUBLIC(ptr, length, &v->pubInfo) || tpm_unmarshal_TPM_AUTHDATA(ptr, length, &v->authValue) || tpm_unmarshal_UINT32(ptr, length, &v->dataIndex)) return -1; return 0; } int tpm_marshal_TPM_DELEGATIONS(BYTE **ptr, UINT32 *length, TPM_DELEGATIONS *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_UINT32(ptr, length, v->delegateType) || tpm_marshal_UINT32(ptr, length, v->per1) || tpm_marshal_UINT32(ptr, length, v->per2)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATIONS(BYTE **ptr, UINT32 *length, TPM_DELEGATIONS *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT32(ptr, length, &v->delegateType) || tpm_unmarshal_UINT32(ptr, length, &v->per1) || tpm_unmarshal_UINT32(ptr, length, &v->per2)) return -1; return 0; } int tpm_marshal_TPM_FAMILY_LABEL(BYTE **ptr, UINT32 *length, TPM_FAMILY_LABEL *v) { if (tpm_marshal_BYTE(ptr, length, v->label)) return -1; return 0; } int tpm_unmarshal_TPM_FAMILY_LABEL(BYTE **ptr, UINT32 *length, TPM_FAMILY_LABEL *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->label)) return -1; return 0; } int tpm_marshal_TPM_FAMILY_TABLE_ENTRY(BYTE **ptr, UINT32 *length, TPM_FAMILY_TABLE_ENTRY *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_FAMILY_LABEL(ptr, length, &v->familyLabel) || tpm_marshal_TPM_FAMILY_ID(ptr, length, v->familyID) || tpm_marshal_TPM_FAMILY_VERIFICATION(ptr, length, v->verificationCount) || tpm_marshal_TPM_FAMILY_FLAGS(ptr, length, v->flags)) return -1; return 0; } int tpm_unmarshal_TPM_FAMILY_TABLE_ENTRY(BYTE **ptr, UINT32 *length, TPM_FAMILY_TABLE_ENTRY *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_FAMILY_LABEL(ptr, length, &v->familyLabel) || tpm_unmarshal_TPM_FAMILY_ID(ptr, length, &v->familyID) || tpm_unmarshal_TPM_FAMILY_VERIFICATION(ptr, length, &v->verificationCount) || tpm_unmarshal_TPM_FAMILY_FLAGS(ptr, length, &v->flags)) return -1; return 0; } int tpm_marshal_TPM_DELEGATE_LABEL(BYTE **ptr, UINT32 *length, TPM_DELEGATE_LABEL *v) { if (tpm_marshal_BYTE(ptr, length, v->label)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATE_LABEL(BYTE **ptr, UINT32 *length, TPM_DELEGATE_LABEL *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->label)) return -1; return 0; } int tpm_marshal_TPM_DELEGATE_PUBLIC(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DELEGATE_LABEL(ptr, length, &v->rowLabel) || tpm_marshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfo) || tpm_marshal_TPM_DELEGATIONS(ptr, length, &v->permissions) || tpm_marshal_TPM_FAMILY_ID(ptr, length, v->familyID) || tpm_marshal_TPM_FAMILY_VERIFICATION(ptr, length, v->verificationCount)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATE_PUBLIC(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DELEGATE_LABEL(ptr, length, &v->rowLabel) || tpm_unmarshal_TPM_PCR_INFO_SHORT(ptr, length, &v->pcrInfo) || tpm_unmarshal_TPM_DELEGATIONS(ptr, length, &v->permissions) || tpm_unmarshal_TPM_FAMILY_ID(ptr, length, &v->familyID) || tpm_unmarshal_TPM_FAMILY_VERIFICATION(ptr, length, &v->verificationCount)) return -1; return 0; } int tpm_marshal_TPM_DELEGATE_PUBLIC_ARRAY(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v, UINT32 n) { UINT32 i; for (i = 0; i < n; i++) { if (tpm_marshal_TPM_DELEGATE_PUBLIC(ptr, length, &v[i])) return -1; } return 0; } int tpm_unmarshal_TPM_DELEGATE_PUBLIC_ARRAY(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v, UINT32 n) { UINT32 i; for (i = 0; i < n; i++) { if (tpm_unmarshal_TPM_DELEGATE_PUBLIC(ptr, length, &v[i])) return -1; } return 0; } int tpm_marshal_TPM_DELEGATE_TABLE_ROW(BYTE **ptr, UINT32 *length, TPM_DELEGATE_TABLE_ROW *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DELEGATE_PUBLIC(ptr, length, &v->pub) || tpm_marshal_TPM_SECRET(ptr, length, &v->authValue)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATE_TABLE_ROW(BYTE **ptr, UINT32 *length, TPM_DELEGATE_TABLE_ROW *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DELEGATE_PUBLIC(ptr, length, &v->pub) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->authValue)) return -1; return 0; } int tpm_marshal_TPM_DELEGATE_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DELEGATE_SENSITIVE *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_SECRET(ptr, length, &v->authValue)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATE_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DELEGATE_SENSITIVE *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->authValue)) return -1; return 0; } int tpm_marshal_TPM_DELEGATE_OWNER_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_OWNER_BLOB *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DELEGATE_PUBLIC(ptr, length, &v->pub) || tpm_marshal_TPM_DIGEST(ptr, length, &v->integrityDigest) || tpm_marshal_UINT32(ptr, length, v->additionalSize) || tpm_marshal_BLOB(ptr, length, v->additionalArea, v->additionalSize) || tpm_marshal_UINT32(ptr, length, v->sensitiveSize) || tpm_marshal_BLOB(ptr, length, v->sensitiveArea, v->sensitiveSize)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_OWNER_BLOB *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DELEGATE_PUBLIC(ptr, length, &v->pub) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->integrityDigest) || tpm_unmarshal_UINT32(ptr, length, &v->additionalSize) || tpm_unmarshal_BLOB(ptr, length, &v->additionalArea, v->additionalSize) || tpm_unmarshal_UINT32(ptr, length, &v->sensitiveSize) || tpm_unmarshal_BLOB(ptr, length, &v->sensitiveArea, v->sensitiveSize)) return -1; return 0; } int tpm_marshal_TPM_DELEGATE_KEY_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_KEY_BLOB *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_DELEGATE_PUBLIC(ptr, length, &v->pub) || tpm_marshal_TPM_DIGEST(ptr, length, &v->integrityDigest) || tpm_marshal_TPM_DIGEST(ptr, length, &v->pubKeyDigest) || tpm_marshal_UINT32(ptr, length, v->additionalSize) || tpm_marshal_BLOB(ptr, length, v->additionalArea, v->additionalSize) || tpm_marshal_UINT32(ptr, length, v->sensitiveSize) || tpm_marshal_BLOB(ptr, length, v->sensitiveArea, v->sensitiveSize)) return -1; return 0; } int tpm_unmarshal_TPM_DELEGATE_KEY_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_KEY_BLOB *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_DELEGATE_PUBLIC(ptr, length, &v->pub) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->integrityDigest) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->pubKeyDigest) || tpm_unmarshal_UINT32(ptr, length, &v->additionalSize) || tpm_unmarshal_BLOB(ptr, length, &v->additionalArea, v->additionalSize) || tpm_unmarshal_UINT32(ptr, length, &v->sensitiveSize) || tpm_unmarshal_BLOB(ptr, length, &v->sensitiveArea, v->sensitiveSize)) return -1; return 0; } int tpm_marshal_TPM_PERMANENT_FLAGS(BYTE **ptr, UINT32 *length, TPM_PERMANENT_FLAGS *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BOOL(ptr, length, v->disable) || tpm_marshal_BOOL(ptr, length, v->ownership) || tpm_marshal_BOOL(ptr, length, v->deactivated) || tpm_marshal_BOOL(ptr, length, v->readPubek) || tpm_marshal_BOOL(ptr, length, v->disableOwnerClear) || tpm_marshal_BOOL(ptr, length, v->allowMaintenance) || tpm_marshal_BOOL(ptr, length, v->physicalPresenceLifetimeLock) || tpm_marshal_BOOL(ptr, length, v->physicalPresenceHWEnable) || tpm_marshal_BOOL(ptr, length, v->physicalPresenceCMDEnable) || tpm_marshal_BOOL(ptr, length, v->CEKPUsed) || tpm_marshal_BOOL(ptr, length, v->TPMpost) || tpm_marshal_BOOL(ptr, length, v->TPMpostLock) || tpm_marshal_BOOL(ptr, length, v->FIPS) || tpm_marshal_BOOL(ptr, length, v->operator) || tpm_marshal_BOOL(ptr, length, v->enableRevokeEK) || tpm_marshal_BOOL(ptr, length, v->nvLocked) || tpm_marshal_BOOL(ptr, length, v->readSRKPub) || tpm_marshal_BOOL(ptr, length, v->tpmEstablished) || tpm_marshal_BOOL(ptr, length, v->maintenanceDone) || tpm_marshal_BOOL(ptr, length, v->disableFullDALogicInfo)) return -1; return 0; } int tpm_unmarshal_TPM_PERMANENT_FLAGS(BYTE **ptr, UINT32 *length, TPM_PERMANENT_FLAGS *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BOOL(ptr, length, &v->disable) || tpm_unmarshal_BOOL(ptr, length, &v->ownership) || tpm_unmarshal_BOOL(ptr, length, &v->deactivated) || tpm_unmarshal_BOOL(ptr, length, &v->readPubek) || tpm_unmarshal_BOOL(ptr, length, &v->disableOwnerClear) || tpm_unmarshal_BOOL(ptr, length, &v->allowMaintenance) || tpm_unmarshal_BOOL(ptr, length, &v->physicalPresenceLifetimeLock) || tpm_unmarshal_BOOL(ptr, length, &v->physicalPresenceHWEnable) || tpm_unmarshal_BOOL(ptr, length, &v->physicalPresenceCMDEnable) || tpm_unmarshal_BOOL(ptr, length, &v->CEKPUsed) || tpm_unmarshal_BOOL(ptr, length, &v->TPMpost) || tpm_unmarshal_BOOL(ptr, length, &v->TPMpostLock) || tpm_unmarshal_BOOL(ptr, length, &v->FIPS) || tpm_unmarshal_BOOL(ptr, length, &v->operator) || tpm_unmarshal_BOOL(ptr, length, &v->enableRevokeEK) || tpm_unmarshal_BOOL(ptr, length, &v->nvLocked) || tpm_unmarshal_BOOL(ptr, length, &v->readSRKPub) || tpm_unmarshal_BOOL(ptr, length, &v->tpmEstablished) || tpm_unmarshal_BOOL(ptr, length, &v->maintenanceDone) || tpm_unmarshal_BOOL(ptr, length, &v->disableFullDALogicInfo)) return -1; return 0; } int tpm_marshal_TPM_STCLEAR_FLAGS(BYTE **ptr, UINT32 *length, TPM_STCLEAR_FLAGS *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BOOL(ptr, length, v->deactivated) || tpm_marshal_BOOL(ptr, length, v->disableForceClear) || tpm_marshal_BOOL(ptr, length, v->physicalPresence) || tpm_marshal_BOOL(ptr, length, v->physicalPresenceLock) || tpm_marshal_BOOL(ptr, length, v->bGlobalLock)) return -1; return 0; } int tpm_unmarshal_TPM_STCLEAR_FLAGS(BYTE **ptr, UINT32 *length, TPM_STCLEAR_FLAGS *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BOOL(ptr, length, &v->deactivated) || tpm_unmarshal_BOOL(ptr, length, &v->disableForceClear) || tpm_unmarshal_BOOL(ptr, length, &v->physicalPresence) || tpm_unmarshal_BOOL(ptr, length, &v->physicalPresenceLock) || tpm_unmarshal_BOOL(ptr, length, &v->bGlobalLock)) return -1; return 0; } int tpm_marshal_TPM_STANY_FLAGS(BYTE **ptr, UINT32 *length, TPM_STANY_FLAGS *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_BOOL(ptr, length, v->postInitialise) || tpm_marshal_UINT32(ptr, length, v->localityModifier) || tpm_marshal_BOOL(ptr, length, v->transportExclusive) || tpm_marshal_BOOL(ptr, length, v->TOSPresent)) return -1; return 0; } int tpm_unmarshal_TPM_STANY_FLAGS(BYTE **ptr, UINT32 *length, TPM_STANY_FLAGS *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_BOOL(ptr, length, &v->postInitialise) || tpm_unmarshal_UINT32(ptr, length, &v->localityModifier) || tpm_unmarshal_BOOL(ptr, length, &v->transportExclusive) || tpm_unmarshal_BOOL(ptr, length, &v->TOSPresent)) return -1; return 0; } int tpm_marshal_RSA(BYTE **ptr, UINT32 *length, tpm_rsa_private_key_t *v) { size_t m_len, e_len, q_len; if (*length < (UINT32)sizeof_RSA((*v))) return -1; if (v->size > 0) { tpm_rsa_export_modulus(v, &(*ptr)[6], &m_len); tpm_rsa_export_exponent(v, &(*ptr)[6+m_len], &e_len); tpm_rsa_export_prime1(v, &(*ptr)[6+m_len+e_len], &q_len); tpm_marshal_UINT16(ptr, length, m_len); tpm_marshal_UINT16(ptr, length, e_len); tpm_marshal_UINT16(ptr, length, q_len); *ptr += m_len + e_len + q_len; *length -= m_len + e_len + q_len; } else { tpm_marshal_UINT16(ptr, length, 0); tpm_marshal_UINT16(ptr, length, 0); tpm_marshal_UINT16(ptr, length, 0); } return 0; } int tpm_unmarshal_RSA(BYTE **ptr, UINT32 *length, tpm_rsa_private_key_t *v) { UINT16 m_len, e_len, q_len; if (tpm_unmarshal_UINT16(ptr, length, &m_len) || tpm_unmarshal_UINT16(ptr, length, &e_len) || tpm_unmarshal_UINT16(ptr, length, &q_len)) return -1; if (m_len == 0) { v->size = 0; return 0; } if (*length < (UINT32)m_len + (UINT32)e_len + (UINT32)q_len || q_len != m_len/2 || tpm_rsa_import_key(v, RSA_MSB_FIRST, &(*ptr)[0], m_len, &(*ptr)[m_len], e_len, &(*ptr)[m_len+e_len], NULL)) return -1; *ptr += m_len + e_len + q_len; *length -= m_len + e_len + q_len; return 0; } int tpm_marshal_RSAPub(BYTE **ptr, UINT32 *length, tpm_rsa_public_key_t *v) { size_t m_len, e_len; if (*length < (UINT32)sizeof_RSAPub((*v))) return -1; if (v->size > 0) { tpm_rsa_export_public_modulus(v, &(*ptr)[4], &m_len); tpm_rsa_export_public_exponent(v, &(*ptr)[4+m_len], &e_len); tpm_marshal_UINT16(ptr, length, m_len); tpm_marshal_UINT16(ptr, length, e_len); *ptr += m_len + e_len; *length -= m_len + e_len; } else { tpm_marshal_UINT16(ptr, length, 0); tpm_marshal_UINT16(ptr, length, 0); } return 0; } int tpm_unmarshal_RSAPub(BYTE **ptr, UINT32 *length, tpm_rsa_public_key_t *v) { UINT16 m_len, e_len; if (tpm_unmarshal_UINT16(ptr, length, &m_len) || tpm_unmarshal_UINT16(ptr, length, &e_len)) return -1; if (m_len == 0) { v->size = 0; return 0; } if (*length < (UINT32)m_len + (UINT32)e_len || tpm_rsa_import_public_key(v, RSA_MSB_FIRST, &(*ptr)[0], m_len, &(*ptr)[m_len], e_len)) return -1; *ptr += m_len + e_len; *length -= m_len + e_len; return 0; } int tpm_marshal_TPM_KEY_DATA(BYTE **ptr, UINT32 *length, TPM_KEY_DATA *v) { if (tpm_marshal_TPM_PAYLOAD_TYPE(ptr, length, v->payload)) return -1; if (v->payload) { if (tpm_marshal_TPM_KEY_USAGE(ptr, length, v->keyUsage) || tpm_marshal_TPM_KEY_FLAGS(ptr, length, v->keyFlags) || tpm_marshal_TPM_KEY_CONTROL(ptr, length, v->keyControl) || tpm_marshal_TPM_AUTH_DATA_USAGE(ptr, length, v->authDataUsage) || tpm_marshal_TPM_ENC_SCHEME(ptr, length, v->encScheme) || tpm_marshal_TPM_SIG_SCHEME(ptr, length, v->sigScheme) || tpm_marshal_TPM_SECRET(ptr, length, &v->usageAuth) || tpm_marshal_TPM_SECRET(ptr, length, &v->migrationAuth) || (v->keyFlags & TPM_KEY_FLAG_HAS_PCR && tpm_marshal_TPM_PCR_INFO(ptr, length, &v->pcrInfo)) || tpm_marshal_BOOL(ptr, length, v->parentPCRStatus) || tpm_marshal_RSA(ptr, length, &v->key)) return -1; } return 0; } int tpm_unmarshal_TPM_KEY_DATA(BYTE **ptr, UINT32 *length, TPM_KEY_DATA *v) { if (tpm_unmarshal_TPM_PAYLOAD_TYPE(ptr, length, &v->payload)) return -1; if (v->payload) { if (tpm_unmarshal_TPM_KEY_USAGE(ptr, length, &v->keyUsage) || tpm_unmarshal_TPM_KEY_FLAGS(ptr, length, &v->keyFlags) || tpm_unmarshal_TPM_KEY_CONTROL(ptr, length, &v->keyControl) || tpm_unmarshal_TPM_AUTH_DATA_USAGE(ptr, length, &v->authDataUsage) || tpm_unmarshal_TPM_ENC_SCHEME(ptr, length, &v->encScheme) || tpm_unmarshal_TPM_SIG_SCHEME(ptr, length, &v->sigScheme) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->usageAuth) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->migrationAuth) || (v->keyFlags & TPM_KEY_FLAG_HAS_PCR && tpm_unmarshal_TPM_PCR_INFO(ptr, length, &v->pcrInfo)) || tpm_unmarshal_BOOL(ptr, length, &v->parentPCRStatus) || tpm_unmarshal_RSA(ptr, length, &v->key)) return -1; } return 0; } int tpm_marshal_TPM_PUBKEY_DATA(BYTE **ptr, UINT32 *length, TPM_PUBKEY_DATA *v) { if (tpm_marshal_BOOL(ptr, length, v->valid)) return -1; if (v->valid) { if (tpm_marshal_TPM_ENC_SCHEME(ptr, length, v->encScheme) || tpm_marshal_TPM_SIG_SCHEME(ptr, length, v->sigScheme) || tpm_marshal_RSAPub(ptr, length, &v->key)) return -1; } return 0; } int tpm_unmarshal_TPM_PUBKEY_DATA(BYTE **ptr, UINT32 *length, TPM_PUBKEY_DATA *v) { if (tpm_unmarshal_BOOL(ptr, length, &v->valid)) return -1; if (v->valid) { if (tpm_unmarshal_TPM_ENC_SCHEME(ptr, length, &v->encScheme) || tpm_unmarshal_TPM_SIG_SCHEME(ptr, length, &v->sigScheme) || tpm_unmarshal_RSAPub(ptr, length, &v->key)) return -1; } return 0; } int tpm_marshal_TPM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, TPM_PERMANENT_DATA *v) { UINT32 i; if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_VERSION(ptr, length, &v->version) || tpm_marshal_TPM_NONCE(ptr, length, &v->tpmProof) || tpm_marshal_TPM_NONCE(ptr, length, &v->ekReset) || tpm_marshal_TPM_SECRET(ptr, length, &v->ownerAuth) || tpm_marshal_TPM_SECRET(ptr, length, &v->operatorAuth) || tpm_marshal_TPM_NONCE(ptr, length, &v->tpmDAASeed) || tpm_marshal_TPM_NONCE(ptr, length, &v->daaProof) || tpm_marshal_TPM_PUBKEY_DATA(ptr, length, &v->manuMaintPub) || tpm_marshal_RSA(ptr, length, &v->endorsementKey) || tpm_marshal_TPM_KEY_DATA(ptr, length, &v->srk) || tpm_marshal_BYTE_ARRAY(ptr, length, v->contextKey, sizeof(v->contextKey)) || tpm_marshal_BYTE_ARRAY(ptr, length, v->delegateKey, sizeof(v->contextKey)) || tpm_marshal_BYTE_ARRAY(ptr, length, v->daaKey, sizeof(v->contextKey)) || tpm_marshal_TPM_ACTUAL_COUNT(ptr, length, v->auditMonotonicCounter)) return -1; for (i = 0; i < TPM_MAX_COUNTERS; i++) { if (tpm_marshal_TPM_COUNTER_VALUE(ptr, length, &v->counters[i]) || tpm_marshal_TPM_SECRET(ptr, length, &v->counters[i].usageAuth) || tpm_marshal_BOOL(ptr, length, v->counters[i].valid)) return -1; } for (i = 0; i < TPM_NUM_PCR; i++) { if (tpm_marshal_TPM_PCR_ATTRIBUTES(ptr, length, &v->pcrAttrib[i])) return -1; } for (i = 0; i < TPM_NUM_PCR; i++) { if (tpm_marshal_TPM_PCRVALUE(ptr, length, &v->pcrValue[i])) return -1; } if (tpm_marshal_BYTE_ARRAY(ptr, length, v->ordinalAuditStatus, sizeof(v->ordinalAuditStatus)) || tpm_marshal_BYTE_ARRAY(ptr, length, v->rngState, sizeof(v->rngState))) return -1; for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { if (tpm_marshal_BOOL(ptr, length, v->familyTable.famRow[i].valid)) return -1; if (v->familyTable.famRow[i].valid) { if (tpm_marshal_TPM_FAMILY_TABLE_ENTRY(ptr, length, &v->familyTable.famRow[i])) return -1; } } for (i = 0; i < TPM_NUM_DELEGATE_TABLE_ENTRY; i++) { if (tpm_marshal_BOOL(ptr, length, v->delegateTable.delRow[i].valid)) return -1; if (v->delegateTable.delRow[i].valid) { if (tpm_marshal_TPM_DELEGATE_TABLE_ROW(ptr, length, &v->delegateTable.delRow[i])) return -1; } } if (tpm_marshal_UINT32(ptr, length, v->lastFamilyID) || tpm_marshal_TPM_CMK_DELEGATE(ptr, length, v->restrictDelegate) || tpm_marshal_UINT32(ptr, length, v->maxNVBufSize) || tpm_marshal_UINT32(ptr, length, v->noOwnerNVWrite) || tpm_marshal_UINT32(ptr, length, v->nvDataSize) || tpm_marshal_BYTE_ARRAY(ptr, length, v->nvData, sizeof(v->nvData))) return -1; for (i = 0; i < TPM_MAX_NVS; i++) { if (tpm_marshal_BOOL(ptr, length, v->nvStorage[i].valid)) return -1; if (v->nvStorage[i].valid) { if (tpm_marshal_TPM_NV_DATA_SENSITIVE(ptr, length, &v->nvStorage[i])) return -1; } } for (i = 0; i < TPM_MAX_KEYS; i++) { if (tpm_marshal_TPM_KEY_DATA(ptr, length, &v->keys[i])) return -1; } if (tpm_marshal_UINT32_ARRAY(ptr, length, v->tis_timeouts, TPM_NUM_TIS_TIMEOUTS) || tpm_marshal_UINT32_ARRAY(ptr, length, v->cmd_durations, TPM_NUM_CMD_DURATIONS)) return -1; return 0; } int tpm_unmarshal_TPM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, TPM_PERMANENT_DATA *v) { UINT32 i; if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_VERSION(ptr, length, &v->version) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->tpmProof) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->ekReset) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->ownerAuth) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->operatorAuth) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->tpmDAASeed) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->daaProof) || tpm_unmarshal_TPM_PUBKEY_DATA(ptr, length, &v->manuMaintPub) || tpm_unmarshal_RSA(ptr, length, &v->endorsementKey) || tpm_unmarshal_TPM_KEY_DATA(ptr, length, &v->srk) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->contextKey, sizeof(v->contextKey)) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->delegateKey, sizeof(v->contextKey)) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->daaKey, sizeof(v->contextKey)) || tpm_unmarshal_TPM_ACTUAL_COUNT(ptr, length, &v->auditMonotonicCounter)) return -1; for (i = 0; i < TPM_MAX_COUNTERS; i++) { if (tpm_unmarshal_TPM_COUNTER_VALUE(ptr, length, &v->counters[i]) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->counters[i].usageAuth) || tpm_unmarshal_BOOL(ptr, length, &v->counters[i].valid)) return -1; } for (i = 0; i < TPM_NUM_PCR; i++) { if (tpm_unmarshal_TPM_PCR_ATTRIBUTES(ptr, length, &v->pcrAttrib[i])) return -1; } for (i = 0; i < TPM_NUM_PCR; i++) { if (tpm_unmarshal_TPM_PCRVALUE(ptr, length, &v->pcrValue[i])) return -1; } if (tpm_unmarshal_BYTE_ARRAY(ptr, length, v->ordinalAuditStatus, sizeof(v->ordinalAuditStatus)) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->rngState, sizeof(v->rngState))) return -1; for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { if (tpm_unmarshal_BOOL(ptr, length, &v->familyTable.famRow[i].valid)) return -1; if (v->familyTable.famRow[i].valid) { if (tpm_unmarshal_TPM_FAMILY_TABLE_ENTRY(ptr, length, &v->familyTable.famRow[i])) return -1; } } for (i = 0; i < TPM_NUM_DELEGATE_TABLE_ENTRY; i++) { if (tpm_unmarshal_BOOL(ptr, length, &v->delegateTable.delRow[i].valid)) return -1; if (v->delegateTable.delRow[i].valid) { if (tpm_unmarshal_TPM_DELEGATE_TABLE_ROW(ptr, length, &v->delegateTable.delRow[i])) return -1; } } if (tpm_unmarshal_UINT32(ptr, length, &v->lastFamilyID) || tpm_unmarshal_TPM_CMK_DELEGATE(ptr, length, &v->restrictDelegate) || tpm_unmarshal_UINT32(ptr, length, &v->maxNVBufSize) || tpm_unmarshal_UINT32(ptr, length, &v->noOwnerNVWrite) || tpm_unmarshal_UINT32(ptr, length, &v->nvDataSize) || tpm_unmarshal_BYTE_ARRAY(ptr, length, v->nvData, sizeof(v->nvData))) return -1; for (i = 0; i < TPM_MAX_NVS; i++) { if (tpm_unmarshal_BOOL(ptr, length, &v->nvStorage[i].valid)) return -1; if (v->nvStorage[i].valid) { if (tpm_unmarshal_TPM_NV_DATA_SENSITIVE(ptr, length, &v->nvStorage[i])) return -1; } } for (i = 0; i < TPM_MAX_KEYS; i++) { if (tpm_unmarshal_TPM_KEY_DATA(ptr, length, &v->keys[i])) return -1; } if (tpm_unmarshal_UINT32_ARRAY(ptr, length, v->tis_timeouts, TPM_NUM_TIS_TIMEOUTS) || tpm_unmarshal_UINT32_ARRAY(ptr, length, v->cmd_durations, TPM_NUM_CMD_DURATIONS)) return -1; return 0; } int tpm_marshal_TPM_STCLEAR_DATA(BYTE **ptr, UINT32 *length, TPM_STCLEAR_DATA *v) { if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_NONCE(ptr, length, &v->contextNonceKey) || tpm_marshal_TPM_COUNT_ID(ptr, length, v->countID) || tpm_marshal_UINT32(ptr, length, v->ownerReference) || tpm_marshal_BOOL(ptr, length, v->disableResetLock) || tpm_marshal_UINT32(ptr, length, v->deferredPhysicalPresence)) return -1; return 0; } int tpm_unmarshal_TPM_STCLEAR_DATA(BYTE **ptr, UINT32 *length, TPM_STCLEAR_DATA *v) { if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->contextNonceKey) || tpm_unmarshal_TPM_COUNT_ID(ptr, length, &v->countID) || tpm_unmarshal_UINT32(ptr, length, &v->ownerReference) || tpm_unmarshal_BOOL(ptr, length, &v->disableResetLock) || tpm_unmarshal_UINT32(ptr, length, &v->deferredPhysicalPresence)) return -1; return 0; } int tpm_marshal_TPM_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_SESSION_DATA *v) { if (tpm_marshal_BYTE(ptr, length, v->type) || tpm_marshal_TPM_NONCE(ptr, length, &v->nonceEven) || tpm_marshal_TPM_NONCE(ptr, length, &v->lastNonceEven) || tpm_marshal_TPM_SECRET(ptr, length, &v->sharedSecret) || tpm_marshal_TPM_HANDLE(ptr, length, v->handle) || tpm_marshal_TPM_ENTITY_TYPE(ptr, length, v->entityType) || (v->type == TPM_ST_DSAP && (tpm_marshal_TPM_DELEGATIONS(ptr, length, &v->permissions) || tpm_marshal_TPM_FAMILY_ID(ptr, length, v->familyID))) || (v->type == TPM_ST_TRANSPORT && tpm_marshal_TPM_TRANSPORT_INTERNAL(ptr, length, &v->transInternal))) return -1; return 0; } int tpm_unmarshal_TPM_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_SESSION_DATA *v) { if (tpm_unmarshal_BYTE(ptr, length, &v->type) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->nonceEven) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->lastNonceEven) || tpm_unmarshal_TPM_SECRET(ptr, length, &v->sharedSecret) || tpm_unmarshal_TPM_HANDLE(ptr, length, &v->handle) || tpm_unmarshal_TPM_ENTITY_TYPE(ptr, length, &v->entityType) || (v->type == TPM_ST_DSAP && (tpm_unmarshal_TPM_DELEGATIONS(ptr, length, &v->permissions) || tpm_unmarshal_TPM_FAMILY_ID(ptr, length, &v->familyID))) || (v->type == TPM_ST_TRANSPORT && tpm_unmarshal_TPM_TRANSPORT_INTERNAL(ptr, length, &v->transInternal))) return -1; return 0; } int tpm_marshal_TPM_STANY_DATA(BYTE **ptr, UINT32 *length, TPM_STANY_DATA *v) { UINT32 i; if (tpm_marshal_TPM_STRUCTURE_TAG(ptr, length, v->tag) || tpm_marshal_TPM_NONCE(ptr, length, &v->contextNonceSession) || tpm_marshal_TPM_DIGEST(ptr, length, &v->auditDigest) || tpm_marshal_BOOL(ptr, length, v->auditSession) || tpm_marshal_TPM_CURRENT_TICKS(ptr, length, &v->currentTicks) || tpm_marshal_UINT32(ptr, length, v->contextCount) || tpm_marshal_UINT32_ARRAY(ptr, length, v->contextList, TPM_MAX_SESSION_LIST)) return -1; for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpm_marshal_TPM_SESSION_DATA(ptr, length, &v->sessions[i])) return -1; } for (i = 0; i < TPM_MAX_SESSIONS_DAA; i++) { if (tpm_marshal_TPM_DAA_SESSION_DATA(ptr, length, &v->sessionsDAA[i])) return -1; } if (tpm_marshal_DAAHANDLE(ptr, length, v->currentDAA) || tpm_marshal_TPM_TRANSHANDLE(ptr, length, v->transExclusive)) return -1; return 0; } int tpm_unmarshal_TPM_STANY_DATA(BYTE **ptr, UINT32 *length, TPM_STANY_DATA *v) { UINT32 i; if (tpm_unmarshal_TPM_STRUCTURE_TAG(ptr, length, &v->tag) || tpm_unmarshal_TPM_NONCE(ptr, length, &v->contextNonceSession) || tpm_unmarshal_TPM_DIGEST(ptr, length, &v->auditDigest) || tpm_unmarshal_BOOL(ptr, length, &v->auditSession) || tpm_unmarshal_TPM_CURRENT_TICKS(ptr, length, &v->currentTicks) || tpm_unmarshal_UINT32(ptr, length, &v->contextCount) || tpm_unmarshal_UINT32_ARRAY(ptr, length, v->contextList, TPM_MAX_SESSION_LIST)) return -1; for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpm_unmarshal_TPM_SESSION_DATA(ptr, length, &v->sessions[i])) return -1; } for (i = 0; i < TPM_MAX_SESSIONS_DAA; i++) { if (tpm_unmarshal_TPM_DAA_SESSION_DATA(ptr, length, &v->sessionsDAA[i])) return -1; } if (tpm_unmarshal_DAAHANDLE(ptr, length, &v->currentDAA) || tpm_unmarshal_TPM_TRANSHANDLE(ptr, length, &v->transExclusive)) return -1; return 0; } int tpm_marshal_TPM_DATA(BYTE **ptr, UINT32 *length, TPM_DATA *v) { if (tpm_marshal_TPM_PERMANENT_FLAGS(ptr, length, &v->permanent.flags) || tpm_marshal_BOOL(ptr, length, v->permanent.flags.selfTestSucceeded) || tpm_marshal_BOOL(ptr, length, v->permanent.flags.owned) || tpm_marshal_TPM_PERMANENT_DATA(ptr, length, &v->permanent.data) || tpm_marshal_TPM_STCLEAR_FLAGS(ptr, length, &v->stclear.flags) || tpm_marshal_TPM_STCLEAR_DATA(ptr, length, &v->stclear.data) || tpm_marshal_TPM_STANY_DATA(ptr, length, &v->stany.data)) return -1; return 0; } int tpm_unmarshal_TPM_DATA(BYTE **ptr, UINT32 *length, TPM_DATA *v) { if (tpm_unmarshal_TPM_PERMANENT_FLAGS(ptr, length, &v->permanent.flags) || tpm_unmarshal_BOOL(ptr, length, &v->permanent.flags.selfTestSucceeded) || tpm_unmarshal_BOOL(ptr, length, &v->permanent.flags.owned) || tpm_unmarshal_TPM_PERMANENT_DATA(ptr, length, &v->permanent.data) || tpm_unmarshal_TPM_STCLEAR_FLAGS(ptr, length, &v->stclear.flags) || tpm_unmarshal_TPM_STCLEAR_DATA(ptr, length, &v->stclear.data) || tpm_unmarshal_TPM_STANY_DATA(ptr, length, &v->stany.data)) return -1; return 0; } int tpm_marshal_TPM_RESPONSE(BYTE **ptr, UINT32 *length, TPM_RESPONSE *v) { if (tpm_marshal_TPM_TAG(ptr, length, v->tag) || tpm_marshal_UINT32(ptr, length, v->size) || tpm_marshal_TPM_RESULT(ptr, length, v->result) || tpm_marshal_BLOB(ptr, length, v->param, v->paramSize)) return -1; if (v->tag == TPM_TAG_RSP_AUTH2_COMMAND) { if (tpm_marshal_TPM_AUTH(ptr, length, v->auth1) || tpm_marshal_TPM_AUTH(ptr, length, v->auth2)) return -1; } else if (v->tag == TPM_TAG_RSP_AUTH1_COMMAND) { if (tpm_marshal_TPM_AUTH(ptr, length, v->auth1)) return -1; } return 0; } int tpm_unmarshal_TPM_REQUEST(BYTE **ptr, UINT32 *length, TPM_REQUEST *v) { if (tpm_unmarshal_TPM_TAG(ptr, length, &v->tag) || tpm_unmarshal_UINT32(ptr, length, &v->size) || tpm_unmarshal_TPM_COMMAND_CODE(ptr, length, &v->ordinal)) return -1; v->param = *ptr; v->paramSize = *length; if (v->tag == TPM_TAG_RQU_AUTH2_COMMAND) { if (*length < 2 * 45) return -1; v->paramSize = *length - 2 * 45; if (tpm_unmarshal_BLOB(ptr, length, &v->param, v->paramSize) || tpm_unmarshal_TPM_AUTH(ptr, length, &v->auth1) || tpm_unmarshal_TPM_AUTH(ptr, length, &v->auth2)) return -1; v->auth1.ordinal = v->ordinal; v->auth2.ordinal = v->ordinal; } else if (v->tag == TPM_TAG_RQU_AUTH1_COMMAND) { if (*length < 45) return -1; v->paramSize = *length - 45; if (tpm_unmarshal_BLOB(ptr, length, &v->param, v->paramSize) || tpm_unmarshal_TPM_AUTH(ptr, length, &v->auth1)) return -1; v->auth1.ordinal = v->ordinal; v->auth2.authHandle = TPM_INVALID_HANDLE; } else { v->auth1.authHandle = TPM_INVALID_HANDLE; v->auth2.authHandle = TPM_INVALID_HANDLE; } return 0; } ================================================ FILE: tpm/tpm_marshalling.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_marshalling.h 384 2010-02-17 14:17:43Z mast $ */ #ifndef _TPM_MARSHALLING_H_ #define _TPM_MARSHALLING_H_ #include "tpm_emulator.h" #include "tpm_structures.h" /* * The following functions perform the data marshalling of all * TPM structures (as defined in [TPM_Part2]) which are used * either as an input or an output parameter by one of the * TPM commands (as defined in [TPM_Part3]). */ /** * tpm_marshal_TYPE - marshals a value of type TYPE * @ptr: target buffer to store the marshalled value into * @length: length of the target buffer * @v: value to marshal * Returns: 0 on success, -1 otherwise * * Description: Performs the data marshalling for values of type TYPE. * On success 0 is returned and the values of ptr as well as length are * updated (i.e., ptr := ptr + sizeof(marshalled value) and length := * length - sizeof(marshalled value)). In case of an error, -1 is * returned and the values of ptr and length are undefined. */ /** * tpm_unmarshal_TYPE - unmarshals a value of type TYPE * @ptr: source buffer containing the marshalled value * @length: length of the source buffer * @v: variable to store the unmarshalled value into * Returns: 0 on success, -1 otherwise * * Description: Performs the data unmarshalling for values of type TYPE. * On success 0 is returned and the values of ptr as well as length are * updated (i.e., ptr := ptr + sizeof(marshalled value) and length := * length - sizeof(marshalled value)). In case of an error, -1 is * returned and the values of ptr and length are undefined. */ static inline int tpm_marshal_BYTE(BYTE **ptr, UINT32 *length, BYTE v) { if (*length < 1) return -1; **ptr = v; *ptr += 1; *length -= 1; return 0; } static inline int tpm_unmarshal_BYTE(BYTE **ptr, UINT32 *length, BYTE *v) { if (*length < 1) return -1; *v = **ptr; *ptr += 1; *length -= 1; return 0; } static inline int tpm_marshal_UINT16(BYTE **ptr, UINT32 *length, UINT16 v) { if (*length < 2) return -1; (*ptr)[0] = (BYTE)((v >> 8) & 0xff); (*ptr)[1] = (BYTE)(v & 0xff); *ptr += 2; *length -= 2; return 0; } static inline int tpm_unmarshal_UINT16(BYTE **ptr, UINT32 *length, UINT16 *v) { if (*length < 2) return -1; *v = (((UINT16)(*ptr)[0] << 8) | (*ptr)[1]); *ptr += 2; *length -= 2; return 0; } static inline int tpm_marshal_UINT32(BYTE **ptr, UINT32 *length, UINT32 v) { if (*length < 4) return -1; (*ptr)[0] = (BYTE)((v >> 24) & 0xff); (*ptr)[1] = (BYTE)((v >> 16) & 0xff); (*ptr)[2] = (BYTE)((v >> 8) & 0xff); (*ptr)[3] = (BYTE)(v & 0xff); *ptr += 4; *length -= 4; return 0; } static inline int tpm_unmarshal_UINT32(BYTE **ptr, UINT32 *length, UINT32 *v) { if (*length < 4) return -1; *v = (((UINT32)(*ptr)[0] << 24) | ((UINT32)(*ptr)[1] << 16) | ((UINT32)(*ptr)[2] << 8) | (*ptr)[3]); *ptr += 4; *length -= 4; return 0; } static inline int tpm_marshal_UINT64(BYTE **ptr, UINT32 *length, UINT64 v) { if (*length < 8) return -1; (*ptr)[0] = (BYTE)((v >> 56) & 0xff); (*ptr)[1] = (BYTE)((v >> 48) & 0xff); (*ptr)[2] = (BYTE)((v >> 40) & 0xff); (*ptr)[3] = (BYTE)((v >> 32) & 0xff); (*ptr)[4] = (BYTE)((v >> 24) & 0xff); (*ptr)[5] = (BYTE)((v >> 16) & 0xff); (*ptr)[6] = (BYTE)((v >> 8) & 0xff); (*ptr)[7] = (BYTE)(v & 0xff); *ptr += 8; *length -= 8; return 0; } static inline int tpm_unmarshal_UINT64(BYTE **ptr, UINT32 *length, UINT64 *v) { if (*length < 8) return -1; *v = (((UINT64)(*ptr)[0] << 56) | ((UINT64)(*ptr)[1] << 48) | ((UINT64)(*ptr)[2] << 40) | ((UINT64)(*ptr)[3] << 32) | ((UINT64)(*ptr)[4] << 24) | ((UINT64)(*ptr)[5] << 16) | ((UINT64)(*ptr)[6] << 8) | (*ptr)[7]); *ptr += 8; *length -= 8; return 0; } static inline int tpm_marshal_BLOB(BYTE **ptr, UINT32 *ptr_length, BYTE *b, UINT32 b_length) { if (*ptr_length < b_length) return -1; if (b_length) memcpy(*ptr, b, b_length); *ptr += b_length; *ptr_length -= b_length; return 0; } static inline int tpm_unmarshal_BLOB(BYTE **ptr, UINT32 *ptr_length, BYTE **b, UINT32 b_length) { if (*ptr_length < b_length) return -1; *b = (b_length) ? *ptr : NULL; *ptr += b_length; *ptr_length -= b_length; return 0; } static inline int tpm_marshal_BYTE_ARRAY(BYTE **ptr, UINT32 *ptr_length, BYTE *b, UINT32 b_length) { if (*ptr_length < b_length) return -1; memcpy(*ptr, b, b_length); *ptr += b_length; *ptr_length -= b_length; return 0; } static inline int tpm_unmarshal_BYTE_ARRAY(BYTE **ptr, UINT32 *ptr_length, BYTE *b, UINT32 b_length) { if (*ptr_length < b_length) return -1; if (b_length) memcpy(b, *ptr, b_length); *ptr += b_length; *ptr_length -= b_length; return 0; } static inline int tpm_marshal_BOOL(BYTE **ptr, UINT32 *length, BOOL v) { if (*length < 1) return -1; **ptr = v & 0x01; *ptr += 1; *length -= 1; return 0; } static inline int tpm_unmarshal_BOOL(BYTE **ptr, UINT32 *length, BOOL *v) { if (*length < 1 || (**ptr & 0xfe)) return -1; *v = **ptr; *ptr += 1; *length -= 1; return 0; } #define tpm_marshal_BOOL_ARRAY tpm_marshal_BYTE_ARRAY #define tpm_unmarshal_BOOL_ARRAY tpm_unmarshal_BYTE_ARRAY #define tpm_marshal_TPM_AUTH_DATA_USAGE tpm_marshal_BYTE #define tpm_unmarshal_TPM_AUTH_DATA_USAGE tpm_unmarshal_BYTE #define tpm_marshal_TPM_PAYLOAD_TYPE tpm_marshal_BYTE #define tpm_unmarshal_TPM_PAYLOAD_TYPE tpm_unmarshal_BYTE #define tpm_marshal_TPM_LOCALITY_SELECTION tpm_marshal_BYTE #define tpm_unmarshal_TPM_LOCALITY_SELECTION tpm_unmarshal_BYTE #define tpm_marshal_TPM_TAG tpm_marshal_UINT16 #define tpm_unmarshal_TPM_TAG tpm_unmarshal_UINT16 #define tpm_marshal_TPM_PROTOCOL_ID tpm_marshal_UINT16 #define tpm_unmarshal_TPM_PROTOCOL_ID tpm_unmarshal_UINT16 #define tpm_marshal_TPM_STARTUP_TYPE tpm_marshal_UINT16 #define tpm_unmarshal_TPM_STARTUP_TYPE tpm_unmarshal_UINT16 #define tpm_marshal_TPM_ENC_SCHEME tpm_marshal_UINT16 #define tpm_unmarshal_TPM_ENC_SCHEME tpm_unmarshal_UINT16 #define tpm_marshal_TPM_SIG_SCHEME tpm_marshal_UINT16 #define tpm_unmarshal_TPM_SIG_SCHEME tpm_unmarshal_UINT16 #define tpm_marshal_TPM_MIGRATE_SCHEME tpm_marshal_UINT16 #define tpm_unmarshal_TPM_MIGRATE_SCHEME tpm_unmarshal_UINT16 #define tpm_marshal_TPM_PHYSICAL_PRESENCE tpm_marshal_UINT16 #define tpm_unmarshal_TPM_PHYSICAL_PRESENCE tpm_unmarshal_UINT16 #define tpm_marshal_TPM_ENTITY_TYPE tpm_marshal_UINT16 #define tpm_unmarshal_TPM_ENTITY_TYPE tpm_unmarshal_UINT16 #define tpm_marshal_TPM_KEY_USAGE tpm_marshal_UINT16 #define tpm_unmarshal_TPM_KEY_USAGE tpm_unmarshal_UINT16 #define tpm_marshal_TPM_STRUCTURE_TAG tpm_marshal_UINT16 #define tpm_unmarshal_TPM_STRUCTURE_TAG tpm_unmarshal_UINT16 #define tpm_marshal_TPM_PLATFORM_SPECIFIC tpm_marshal_UINT16 #define tpm_unmarshal_TPM_PLATFORM_SPECIFIC tpm_unmarshal_UINT16 #define tpm_marshal_TPM_EK_TYPE tpm_marshal_UINT16 #define tpm_unmarshal_TPM_EK_TYPE tpm_unmarshal_UINT16 #define tpm_marshal_TPM_COMMAND_CODE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_COMMAND_CODE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_CAPABILITY_AREA tpm_marshal_UINT32 #define tpm_unmarshal_TPM_CAPABILITY_AREA tpm_unmarshal_UINT32 #define tpm_marshal_TPM_KEY_FLAGS tpm_marshal_UINT32 #define tpm_unmarshal_TPM_KEY_FLAGS tpm_unmarshal_UINT32 #define tpm_marshal_TPM_ALGORITHM_ID tpm_marshal_UINT32 #define tpm_unmarshal_TPM_ALGORITHM_ID tpm_unmarshal_UINT32 #define tpm_marshal_TPM_MODIFIER_INDICATOR tpm_marshal_UINT32 #define tpm_unmarshal_TPM_MODIFIER_INDICATOR tpm_unmarshal_UINT32 #define tpm_marshal_TPM_ACTUAL_COUNT tpm_marshal_UINT32 #define tpm_unmarshal_TPM_ACTUAL_COUNT tpm_unmarshal_UINT32 #define tpm_marshal_TPM_TRANSPORT_ATTRIBUTES tpm_marshal_UINT32 #define tpm_unmarshal_TPM_TRANSPORT_ATTRIBUTES tpm_unmarshal_UINT32 #define tpm_marshal_TPM_AUTHHANDLE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_AUTHHANDLE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_RESULT tpm_marshal_UINT32 #define tpm_unmarshal_TPM_RESULT tpm_unmarshal_UINT32 #define tpm_marshal_TPM_DIRINDEX tpm_marshal_UINT32 #define tpm_unmarshal_TPM_DIRINDEX tpm_unmarshal_UINT32 #define tpm_marshal_TPM_KEY_HANDLE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_KEY_HANDLE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_PCRINDEX tpm_marshal_UINT32 #define tpm_unmarshal_TPM_PCRINDEX tpm_unmarshal_UINT32 #define tpm_marshal_TPM_RESOURCE_TYPE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_RESOURCE_TYPE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_KEY_CONTROL tpm_marshal_UINT32 #define tpm_unmarshal_TPM_KEY_CONTROL tpm_unmarshal_UINT32 #define tpm_marshal_TPM_NV_INDEX tpm_marshal_UINT32 #define tpm_unmarshal_TPM_NV_INDEX tpm_unmarshal_UINT32 #define tpm_marshal_TPM_FAMILY_ID tpm_marshal_UINT32 #define tpm_unmarshal_TPM_FAMILY_ID tpm_unmarshal_UINT32 #define tpm_marshal_TPM_FAMILY_VERIFICATION tpm_marshal_UINT32 #define tpm_unmarshal_TPM_FAMILY_VERIFICATION tpm_unmarshal_UINT32 #define tpm_marshal_TPM_STARTUP_EFFECTS tpm_marshal_UINT32 #define tpm_unmarshal_TPM_STARTUP_EFFECTS tpm_unmarshal_UINT32 #define tpm_marshal_TPM_SYM_MODE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_SYM_MODE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_FAMILY_FLAGS tpm_marshal_UINT32 #define tpm_unmarshal_TPM_FAMILY_FLAGS tpm_unmarshal_UINT32 #define tpm_marshal_TPM_DELEGATE_INDEX tpm_marshal_UINT32 #define tpm_unmarshal_TPM_DELEGATE_INDEX tpm_unmarshal_UINT32 #define tpm_marshal_TPM_COUNT_ID tpm_marshal_UINT32 #define tpm_unmarshal_TPM_COUNT_ID tpm_unmarshal_UINT32 #define tpm_marshal_TPM_TRANSHANDLE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_TRANSHANDLE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_HANDLE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_HANDLE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_FAMILY_OPERATION tpm_marshal_UINT32 #define tpm_unmarshal_TPM_FAMILY_OPERATION tpm_unmarshal_UINT32 #define tpm_marshal_TPM_CMK_DELEGATE tpm_marshal_UINT32 #define tpm_unmarshal_TPM_CMK_DELEGATE tpm_unmarshal_UINT32 #define tpm_marshal_TPM_REDIR_COMMAND tpm_marshal_UINT32 #define tpm_unmarshal_TPM_REDIR_COMMAND tpm_unmarshal_UINT32 #define tpm_marshal_DAAHANDLE tpm_marshal_UINT32 #define tpm_unmarshal_DAAHANDLE tpm_unmarshal_UINT32 int tpm_marshal_UINT32_ARRAY(BYTE **ptr, UINT32 *length, UINT32 *v, UINT32 n); int tpm_unmarshal_UINT32_ARRAY(BYTE **ptr, UINT32 *length, UINT32 *v, UINT32 n); int tpm_marshal_TPM_STRUCT_VER(BYTE **ptr, UINT32 *length, TPM_STRUCT_VER *v); int tpm_unmarshal_TPM_STRUCT_VER(BYTE **ptr, UINT32 *length, TPM_STRUCT_VER *v); int tpm_marshal_TPM_VERSION(BYTE **ptr, UINT32 *length, TPM_VERSION *v); int tpm_unmarshal_TPM_VERSION(BYTE **ptr, UINT32 *length, TPM_VERSION *v); int tpm_marshal_TPM_DIGEST(BYTE **ptr, UINT32 *length, TPM_DIGEST *v); int tpm_unmarshal_TPM_DIGEST(BYTE **ptr, UINT32 *length, TPM_DIGEST *v); #define tpm_marshal_TPM_CHOSENID_HASH tpm_marshal_TPM_DIGEST #define tpm_unmarshal_TPM_CHOSENID_HASH tpm_unmarshal_TPM_DIGEST #define tpm_marshal_TPM_COMPOSITE_HASH tpm_marshal_TPM_DIGEST #define tpm_unmarshal_TPM_COMPOSITE_HASH tpm_unmarshal_TPM_DIGEST #define tpm_marshal_TPM_DIRVALUE tpm_marshal_TPM_DIGEST #define tpm_unmarshal_TPM_DIRVALUE tpm_unmarshal_TPM_DIGEST #define tpm_marshal_TPM_HMAC tpm_marshal_TPM_DIGEST #define tpm_unmarshal_TPM_HMAC tpm_unmarshal_TPM_DIGEST #define tpm_marshal_TPM_PCRVALUE tpm_marshal_TPM_DIGEST #define tpm_unmarshal_TPM_PCRVALUE tpm_unmarshal_TPM_DIGEST int tpm_marshal_TPM_PCRVALUE_ARRAY(BYTE **ptr, UINT32 *length, TPM_PCRVALUE *v, UINT32 n); int tpm_unmarshal_TPM_PCRVALUE_ARRAY(BYTE **ptr, UINT32 *length, TPM_PCRVALUE *v, UINT32 n); int tpm_marshal_TPM_NONCE(BYTE **ptr, UINT32 *length, TPM_NONCE *v); int tpm_unmarshal_TPM_NONCE(BYTE **ptr, UINT32 *length, TPM_NONCE *v); int tpm_marshal_TPM_AUTHDATA(BYTE **ptr, UINT32 *length, TPM_AUTHDATA *v); int tpm_unmarshal_TPM_AUTHDATA(BYTE **ptr, UINT32 *length, TPM_AUTHDATA *v); #define tpm_marshal_TPM_SECRET tpm_marshal_TPM_AUTHDATA #define tpm_unmarshal_TPM_SECRET tpm_unmarshal_TPM_AUTHDATA #define tpm_marshal_TPM_ENCAUTH tpm_marshal_TPM_AUTHDATA #define tpm_unmarshal_TPM_ENCAUTH tpm_unmarshal_TPM_AUTHDATA int tpm_marshal_TPM_AUTH(BYTE **ptr, UINT32 *length, TPM_AUTH *v); int tpm_unmarshal_TPM_AUTH(BYTE **ptr, UINT32 *length, TPM_AUTH *v); int tpm_marshal_TPM_KEY_HANDLE_LIST(BYTE **ptr, UINT32 *length, TPM_KEY_HANDLE_LIST *v); int tpm_marshal_TPM_CHANGEAUTH_VALIDATE(BYTE **ptr, UINT32 *length, TPM_CHANGEAUTH_VALIDATE *v); int tpm_unmarshal_TPM_CHANGEAUTH_VALIDATE(BYTE **ptr, UINT32 *length, TPM_CHANGEAUTH_VALIDATE *v); int tpm_marshal_TPM_COUNTER_VALUE(BYTE **ptr, UINT32 *length, TPM_COUNTER_VALUE *v); int tpm_unmarshal_TPM_COUNTER_VALUE(BYTE **ptr, UINT32 *length, TPM_COUNTER_VALUE *v); int tpm_marshal_TPM_PCR_SELECTION(BYTE **ptr, UINT32 *length, TPM_PCR_SELECTION *v); int tpm_unmarshal_TPM_PCR_SELECTION(BYTE **ptr, UINT32 *length, TPM_PCR_SELECTION *v); int tpm_marshal_TPM_PCR_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_PCR_COMPOSITE *v); int tpm_unmarshal_TPM_PCR_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_PCR_COMPOSITE *v); int tpm_marshal_TPM_PCR_INFO(BYTE **ptr, UINT32 *length, TPM_PCR_INFO *v); int tpm_unmarshal_TPM_PCR_INFO(BYTE **ptr, UINT32 *length, TPM_PCR_INFO *v); int tpm_marshal_TPM_PCR_INFO_SHORT(BYTE **ptr, UINT32 *length, TPM_PCR_INFO_SHORT *v); int tpm_unmarshal_TPM_PCR_INFO_SHORT(BYTE **ptr, UINT32 *length, TPM_PCR_INFO_SHORT *v); int tpm_marshal_TPM_PCR_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_PCR_ATTRIBUTES *v); int tpm_unmarshal_TPM_PCR_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_PCR_ATTRIBUTES *v); int tpm_marshal_TPM_STORED_DATA(BYTE **ptr, UINT32 *length, TPM_STORED_DATA *v); int tpm_unmarshal_TPM_STORED_DATA(BYTE **ptr, UINT32 *length, TPM_STORED_DATA *v); int tpm_marshal_TPM_SEALED_DATA(BYTE **ptr, UINT32 *length, TPM_SEALED_DATA *v); int tpm_unmarshal_TPM_SEALED_DATA(BYTE **ptr, UINT32 *length, TPM_SEALED_DATA *v); int tpm_marshal_TPM_SYMMETRIC_KEY(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY *v); int tpm_unmarshal_TPM_SYMMETRIC_KEY(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY *v); int tpm_marshal_TPM_SYMMETRIC_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY_PARMS *v); int tpm_unmarshal_TPM_SYMMETRIC_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_SYMMETRIC_KEY_PARMS *v); int tpm_marshal_TPM_RSA_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_RSA_KEY_PARMS *v); int tpm_unmarshal_TPM_RSA_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_RSA_KEY_PARMS *v); int tpm_marshal_TPM_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_KEY_PARMS *v); int tpm_unmarshal_TPM_KEY_PARMS(BYTE **ptr, UINT32 *length, TPM_KEY_PARMS *v); int tpm_marshal_TPM_STORE_PUBKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PUBKEY *v); int tpm_unmarshal_TPM_STORE_PUBKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PUBKEY *v); int tpm_marshal_TPM_KEY(BYTE **ptr, UINT32 *length, TPM_KEY *v); int tpm_unmarshal_TPM_KEY(BYTE **ptr, UINT32 *length, TPM_KEY *v); int tpm_marshal_TPM_PUBKEY(BYTE **ptr, UINT32 *length, TPM_PUBKEY *v); int tpm_unmarshal_TPM_PUBKEY(BYTE **ptr, UINT32 *length, TPM_PUBKEY *v); int tpm_marshal_TPM_STORE_PRIVKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PRIVKEY *v); int tpm_unmarshal_TPM_STORE_PRIVKEY(BYTE **ptr, UINT32 *length, TPM_STORE_PRIVKEY *v); int tpm_marshal_TPM_STORE_ASYMKEY(BYTE **ptr, UINT32 *length, TPM_STORE_ASYMKEY *v); int tpm_unmarshal_TPM_STORE_ASYMKEY(BYTE **ptr, UINT32 *length, TPM_STORE_ASYMKEY *v); int tpm_marshal_TPM_MIGRATIONKEYAUTH(BYTE **ptr, UINT32 *length, TPM_MIGRATIONKEYAUTH *v); int tpm_unmarshal_TPM_MIGRATIONKEYAUTH(BYTE **ptr, UINT32 *length, TPM_MIGRATIONKEYAUTH *v); int tpm_marshal_TPM_CERTIFY_INFO(BYTE **ptr, UINT32 *length, TPM_CERTIFY_INFO *v); int tpm_unmarshal_TPM_CERTIFY_INFO(BYTE **ptr, UINT32 *length, TPM_CERTIFY_INFO *v); int tpm_marshal_TPM_IDENTITY_CONTENTS(BYTE **ptr, UINT32 *length, TPM_IDENTITY_CONTENTS *v); int tpm_unmarshal_TPM_IDENTITY_CONTENTS(BYTE **ptr, UINT32 *length, TPM_IDENTITY_CONTENTS *v); int tpm_marshal_TPM_CURRENT_TICKS(BYTE **ptr, UINT32 *length, TPM_CURRENT_TICKS *v); int tpm_unmarshal_TPM_CURRENT_TICKS(BYTE **ptr, UINT32 *length, TPM_CURRENT_TICKS *v); int tpm_marshal_TPM_TRANSPORT_PUBLIC(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_PUBLIC *v); int tpm_unmarshal_TPM_TRANSPORT_PUBLIC(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_PUBLIC *v); int tpm_marshal_TPM_TRANSPORT_INTERNAL(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_INTERNAL *v); int tpm_unmarshal_TPM_TRANSPORT_INTERNAL(BYTE **ptr, UINT32 *length, TPM_TRANSPORT_INTERNAL *v); int tpm_marshal_TPM_CONTEXT_BLOB(BYTE **ptr, UINT32 *length, TPM_CONTEXT_BLOB *v); int tpm_unmarshal_TPM_CONTEXT_BLOB(BYTE **ptr, UINT32 *length, TPM_CONTEXT_BLOB *v); int tpm_marshal_TPM_CONTEXT_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_CONTEXT_SENSITIVE *v); int tpm_unmarshal_TPM_CONTEXT_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_CONTEXT_SENSITIVE *v); int tpm_marshal_TPM_DAA_BLOB(BYTE **ptr, UINT32 *length, TPM_DAA_BLOB *v); int tpm_unmarshal_TPM_DAA_BLOB(BYTE **ptr, UINT32 *length, TPM_DAA_BLOB *v); int tpm_marshal_TPM_DAA_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DAA_SENSITIVE *v); int tpm_unmarshal_TPM_DAA_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DAA_SENSITIVE *v); int tpm_marshal_TPM_DAA_ISSUER(BYTE **ptr, UINT32 *length, TPM_DAA_ISSUER *v); int tpm_unmarshal_TPM_DAA_ISSUER(BYTE **ptr, UINT32 *length, TPM_DAA_ISSUER *v); int tpm_marshal_TPM_DAA_TPM(BYTE **ptr, UINT32 *length, TPM_DAA_TPM *v); int tpm_unmarshal_TPM_DAA_TPM(BYTE **ptr, UINT32 *length, TPM_DAA_TPM *v); int tpm_marshal_TPM_DAA_CONTEXT(BYTE **ptr, UINT32 *length, TPM_DAA_CONTEXT *v); int tpm_unmarshal_TPM_DAA_CONTEXT(BYTE **ptr, UINT32 *length, TPM_DAA_CONTEXT *v); int tpm_marshal_TPM_DAA_JOINDATA(BYTE **ptr, UINT32 *length, TPM_DAA_JOINDATA *v); int tpm_unmarshal_TPM_DAA_JOINDATA(BYTE **ptr, UINT32 *length, TPM_DAA_JOINDATA *v); int tpm_marshal_TPM_DAA_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_DAA_SESSION_DATA *v); int tpm_unmarshal_TPM_DAA_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_DAA_SESSION_DATA *v); int tpm_marshal_TPM_MSA_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_MSA_COMPOSITE *v); int tpm_unmarshal_TPM_MSA_COMPOSITE(BYTE **ptr, UINT32 *length, TPM_MSA_COMPOSITE *v); int tpm_marshal_TPM_CMK_AUTH(BYTE **ptr, UINT32 *length, TPM_CMK_AUTH *v); int tpm_unmarshal_TPM_CMK_AUTH(BYTE **ptr, UINT32 *length, TPM_CMK_AUTH *v); int tpm_marshal_TPM_SELECT_SIZE(BYTE **ptr, UINT32 *length, TPM_SELECT_SIZE *v); int tpm_unmarshal_TPM_SELECT_SIZE(BYTE **ptr, UINT32 *length, TPM_SELECT_SIZE *v); int tpm_marshal_TPM_CAP_VERSION_INFO(BYTE **ptr, UINT32 *length, TPM_CAP_VERSION_INFO *v); int tpm_unmarshal_TPM_CAP_VERSION_INFO(BYTE **ptr, UINT32 *length, TPM_CAP_VERSION_INFO *v); int tpm_marshal_TPM_ASYM_CA_CONTENTS(BYTE **ptr, UINT32 *length, TPM_ASYM_CA_CONTENTS *v); int tpm_unmarshal_TPM_ASYM_CA_CONTENTS(BYTE **ptr, UINT32 *length, TPM_ASYM_CA_CONTENTS *v); int tpm_marshal_TPM_QUOTE_INFO2(BYTE **ptr, UINT32 *length, TPM_QUOTE_INFO2 *v); int tpm_unmarshal_TPM_QUOTE_INFO2(BYTE **ptr, UINT32 *length, TPM_QUOTE_INFO2 *v); int tpm_marshal_TPM_EK_BLOB(BYTE **ptr, UINT32 *length, TPM_EK_BLOB *v); int tpm_unmarshal_TPM_EK_BLOB(BYTE **ptr, UINT32 *length, TPM_EK_BLOB *v); int tpm_marshal_TPM_EK_BLOB_ACTIVATE(BYTE **ptr, UINT32 *length, TPM_EK_BLOB_ACTIVATE *v); int tpm_unmarshal_TPM_EK_BLOB_ACTIVATE(BYTE **ptr, UINT32 *length, TPM_EK_BLOB_ACTIVATE *v); int tpm_marshal_TPM_NV_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_NV_ATTRIBUTES *v); int tpm_unmarshal_TPM_NV_ATTRIBUTES(BYTE **ptr, UINT32 *length, TPM_NV_ATTRIBUTES *v); int tpm_marshal_TPM_NV_DATA_PUBLIC(BYTE **ptr, UINT32 *length, TPM_NV_DATA_PUBLIC *v); int tpm_unmarshal_TPM_NV_DATA_PUBLIC(BYTE **ptr, UINT32 *length, TPM_NV_DATA_PUBLIC *v); int tpm_marshal_TPM_DELEGATIONS(BYTE **ptr, UINT32 *length, TPM_DELEGATIONS *v); int tpm_unmarshal_TPM_DELEGATIONS(BYTE **ptr, UINT32 *length, TPM_DELEGATIONS *v); int tpm_marshal_TPM_FAMILY_LABEL(BYTE **ptr, UINT32 *length, TPM_FAMILY_LABEL *v); int tpm_unmarshal_TPM_FAMILY_LABEL(BYTE **ptr, UINT32 *length, TPM_FAMILY_LABEL *v); int tpm_marshal_TPM_FAMILY_TABLE_ENTRY(BYTE **ptr, UINT32 *length, TPM_FAMILY_TABLE_ENTRY *v); int tpm_unmarshal_TPM_FAMILY_TABLE_ENTRY(BYTE **ptr, UINT32 *length, TPM_FAMILY_TABLE_ENTRY *v); int tpm_marshal_TPM_DELEGATE_LABEL(BYTE **ptr, UINT32 *length, TPM_DELEGATE_LABEL *v); int tpm_unmarshal_TPM_DELEGATE_LABEL(BYTE **ptr, UINT32 *length, TPM_DELEGATE_LABEL *v); int tpm_marshal_TPM_DELEGATE_PUBLIC(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v); int tpm_unmarshal_TPM_DELEGATE_PUBLIC(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v); int tpm_marshal_TPM_DELEGATE_PUBLIC_ARRAY(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v, UINT32 n); int tpm_unmarshal_TPM_DELEGATE_PUBLIC_ARRAY(BYTE **ptr, UINT32 *length, TPM_DELEGATE_PUBLIC *v, UINT32 n); int tpm_marshal_TPM_DELEGATE_TABLE_ROW(BYTE **ptr, UINT32 *length, TPM_DELEGATE_TABLE_ROW *v); int tpm_unmarshal_TPM_DELEGATE_TABLE_ROW(BYTE **ptr, UINT32 *length, TPM_DELEGATE_TABLE_ROW *v); int tpm_marshal_TPM_DELEGATE_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DELEGATE_SENSITIVE *v); int tpm_unmarshal_TPM_DELEGATE_SENSITIVE(BYTE **ptr, UINT32 *length, TPM_DELEGATE_SENSITIVE *v); int tpm_marshal_TPM_DELEGATE_OWNER_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_OWNER_BLOB *v); int tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_OWNER_BLOB *v); int tpm_marshal_TPM_DELEGATE_KEY_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_KEY_BLOB *v); int tpm_unmarshal_TPM_DELEGATE_KEY_BLOB(BYTE **ptr, UINT32 *length, TPM_DELEGATE_KEY_BLOB *v); int tpm_marshal_TPM_PERMANENT_FLAGS(BYTE **ptr, UINT32 *length, TPM_PERMANENT_FLAGS *v); int tpm_unmarshal_TPM_PERMANENT_FLAGS(BYTE **ptr, UINT32 *length, TPM_PERMANENT_FLAGS *v); int tpm_marshal_TPM_STCLEAR_FLAGS(BYTE **ptr, UINT32 *length, TPM_STCLEAR_FLAGS *v); int tpm_unmarshal_TPM_STCLEAR_FLAGS(BYTE **ptr, UINT32 *length, TPM_STCLEAR_FLAGS *v); int tpm_marshal_TPM_STANY_FLAGS(BYTE **ptr, UINT32 *length, TPM_STANY_FLAGS *v); int tpm_unmarshal_TPM_STANY_FLAGS(BYTE **ptr, UINT32 *length, TPM_STANY_FLAGS *v); int tpm_marshal_RSA(BYTE **ptr, UINT32 *length, tpm_rsa_private_key_t *v); int tpm_unmarshal_RSA(BYTE **ptr, UINT32 *length, tpm_rsa_private_key_t *v); int tpm_marshal_RSAPub(BYTE **ptr, UINT32 *length, tpm_rsa_public_key_t *v); int tpm_unmarshal_RSAPub(BYTE **ptr, UINT32 *length, tpm_rsa_public_key_t *v); int tpm_marshal_TPM_KEY_DATA(BYTE **ptr, UINT32 *length, TPM_KEY_DATA *v); int tpm_unmarshal_TPM_KEY_DATA(BYTE **ptr, UINT32 *length, TPM_KEY_DATA *v); int tpm_marshal_TPM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, TPM_PERMANENT_DATA *); int tpm_unmarshal_TPM_PERMANENT_DATA(BYTE **ptr, UINT32 *length, TPM_PERMANENT_DATA *); int tpm_marshal_TPM_STCLEAR_DATA(BYTE **ptr, UINT32 *length, TPM_STCLEAR_DATA *v); int tpm_unmarshal_TPM_STCLEAR_DATA(BYTE **ptr, UINT32 *length, TPM_STCLEAR_DATA *v); int tpm_marshal_TPM_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_SESSION_DATA *v); int tpm_unmarshal_TPM_SESSION_DATA(BYTE **ptr, UINT32 *length, TPM_SESSION_DATA *v); int tpm_marshal_TPM_STANY_DATA(BYTE **ptr, UINT32 *length, TPM_STANY_DATA *v); int tpm_unmarshal_TPM_STANY_DATA(BYTE **ptr, UINT32 *length, TPM_STANY_DATA *v); int tpm_unmarshal_TPM_DATA(BYTE **ptr, UINT32 *length, TPM_DATA *v); int tpm_marshal_TPM_DATA(BYTE **ptr, UINT32 *length, TPM_DATA *v); int tpm_marshal_TPM_RESPONSE(BYTE **ptr, UINT32 *length, TPM_RESPONSE *v); int tpm_unmarshal_TPM_REQUEST(BYTE **ptr, UINT32 *length, TPM_REQUEST *v); #endif /* _TPM_MARSHALLING_H_ */ ================================================ FILE: tpm/tpm_migration.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_migration.c 462 2011-06-04 14:14:33Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_handles.h" #include "tpm_data.h" #include "tpm_marshalling.h" #include "crypto/sha1.h" #include "crypto/hmac.h" /* * Migration ([TPM_Part3], Section 11) */ 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 tpm_verify_migration_digest(TPM_MIGRATIONKEYAUTH *migrationKeyAuth, TPM_NONCE *tpmProof) { TPM_DIGEST digest; if (tpm_compute_migration_digest(&migrationKeyAuth->migrationKey, migrationKeyAuth->migrationScheme, tpmProof, &digest)) return -1; return memcmp(digest.digest, migrationKeyAuth->digest.digest, sizeof(TPM_DIGEST)); } 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) { BYTE *ptr, *buf; UINT32 len; size_t buf_len; /* generate an OAEP encoding of the TPM_MIGRATE_ASYMKEY structure: K1|seed|0x00-pad|0x01|TPM_MIGRATE_ASYMKEY */ debug("migrationType = TPM_MS_MIGRATE"); len = buf_len = 198; ptr = buf = tpm_malloc(buf_len); *randomSize = buf_len; *random = tpm_malloc(*randomSize); *outDataSize = key.key.size >> 3; *outData = tpm_malloc(*outDataSize); if (buf == NULL || *random == NULL || *outData == NULL) { free_TPM_PUBKEY_DATA(key); tpm_free(buf); tpm_free(*random); tpm_free(*outData); tpm_free(key_buf); return TPM_NOSPACE; } memset(buf, 0, buf_len); tpm_marshal_UINT32(&ptr, &len, store.privKey.keyLength); memcpy(ptr, store.privKey.key, 16); ptr += 16; memcpy(ptr, store.migrationAuth, sizeof(TPM_SECRET)); len = 46 + store.privKey.keyLength - 16; ptr = &buf[buf_len - len]; tpm_marshal_BYTE(&ptr, &len, 0x01); tpm_marshal_TPM_PAYLOAD_TYPE(&ptr, &len, TPM_PT_MIGRATE); tpm_marshal_TPM_SECRET(&ptr, &len, &store.usageAuth); tpm_marshal_TPM_DIGEST(&ptr, &len, &store.pubDataDigest); tpm_marshal_UINT32(&ptr, &len, store.privKey.keyLength - 16); memcpy(ptr, &store.privKey.key[16], store.privKey.keyLength - 16); tpm_rsa_mask_generation(buf, SHA1_DIGEST_LENGTH, &buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH); tpm_rsa_mask_generation(&buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH, buf, SHA1_DIGEST_LENGTH); /* XOR encrypt OAEP encoding */ tpm_get_random_bytes(*random, *randomSize); for (len = 0; len < buf_len; len++) buf[len] ^= (*random)[len]; /* RSA encrypt OAEP encoding */ if (tpm_rsa_encrypt(&key.key, RSA_ES_OAEP_SHA1, buf, buf_len, *outData, &buf_len)) { debug("tpm_rsa_encrypt() failed"); free_TPM_PUBKEY_DATA(key); tpm_free(buf); tpm_free(*random); tpm_free(*outData); tpm_free(key_buf); return TPM_ENCRYPT_ERROR; } *outDataSize = buf_len; tpm_free(buf); } else { debug("invalid migration type: %d", migrationType); free_TPM_PUBKEY_DATA(key); tpm_free(key_buf); return TPM_BAD_PARAMETER; } free_TPM_PUBKEY_DATA(key); tpm_free(key_buf); return TPM_SUCCESS; } TPM_RESULT TPM_ConvertMigrationBlob(TPM_KEY_HANDLE parentHandle, UINT32 inDataSize, BYTE *inData, UINT32 randomSize, BYTE *random, TPM_AUTH *auth1, UINT32 *outDataSize,BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *parent; BYTE *ptr, *buf; UINT32 len; size_t buf_len; TPM_STORE_ASYMKEY store; info("TPM_ConvertMigrationBlob()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify parent authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || parent->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; } /* verify key properties */ if (parent->keyUsage != TPM_KEY_STORAGE) return TPM_INVALID_KEYUSAGE; /* decrypt private key */ buf_len = parent->key.size >> 3; buf = tpm_malloc(buf_len); if (buf == NULL) return TPM_NOSPACE; /* RSA decrypt OAEP encoding */ if (tpm_rsa_decrypt(&parent->key, RSA_ES_OAEP_SHA1, inData, inDataSize, buf, &buf_len) || buf_len != randomSize || buf_len != 198) { debug("tpm_rsa_decrypt() failed"); tpm_free(buf); return TPM_DECRYPT_ERROR; } /* XOR decrypt OAEP encoding */ for (len = 0; len < buf_len; len++) buf[len] ^= random[len]; /* unmask OAEP encoding */ tpm_rsa_mask_generation(&buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH, buf, SHA1_DIGEST_LENGTH); tpm_rsa_mask_generation(buf, SHA1_DIGEST_LENGTH, &buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH); /* create a TPM_STORE_ASYMKEY structure */ memcpy(store.migrationAuth, &buf[20], sizeof(TPM_SECRET)); for (ptr = &buf[20 + sizeof(TPM_SECRET)]; *ptr == 0x00; ptr++); if (ptr[0] != 0x01 || ptr[1] != TPM_PT_MIGRATE) { debug("OAEP encoding is invalid"); tpm_free(buf); return TPM_DECRYPT_ERROR; } ptr += 2; len = buf_len - (ptr - buf); store.payload = TPM_PT_ASYM; tpm_unmarshal_TPM_SECRET(&ptr, &len, &store.usageAuth); tpm_unmarshal_TPM_DIGEST(&ptr, &len, &store.pubDataDigest); tpm_unmarshal_UINT32(&ptr, &len, &store.privKey.keyLength); store.privKey.keyLength += 16; if (store.privKey.keyLength != len + 16) { error("invalid key length %d; expected %d", store.privKey.keyLength, len + 16); tpm_free(buf); return TPM_DECRYPT_ERROR; } memmove(&buf[20], ptr, len); store.privKey.key = &buf[4]; /* encrypt private key */ *outDataSize = parent->key.size >> 3; *outData = tpm_malloc(*outDataSize); if (*outData == NULL) { tpm_free(buf); return TPM_NOSPACE; } if (tpm_encrypt_private_key(parent, &store, *outData, outDataSize)) { debug("tpm_encrypt_private_key() failed"); tpm_free(*outData); tpm_free(buf); return TPM_ENCRYPT_ERROR; } tpm_free(buf); return TPM_SUCCESS; } static int tpm_copy_pubkey(TPM_PUBKEY *in, TPM_PUBKEY *out) { memcpy(out, in, sizeof(TPM_PUBKEY)); out->pubKey.key = tpm_malloc(out->pubKey.keyLength); if (out->pubKey.key == NULL) return -1; memcpy(out->pubKey.key, in->pubKey.key, out->pubKey.keyLength); out->algorithmParms.parms.rsa.exponent = tpm_malloc(out->algorithmParms.parms.rsa.exponentSize); if (out->algorithmParms.parms.rsa.exponent == NULL) { tpm_free(out->pubKey.key); return -1; } memcpy(out->algorithmParms.parms.rsa.exponent, in->algorithmParms.parms.rsa.exponent, out->algorithmParms.parms.rsa.exponentSize); return 0; } TPM_RESULT TPM_AuthorizeMigrationKey(TPM_MIGRATE_SCHEME migrateScheme, TPM_PUBKEY *migrationKey, TPM_AUTH *auth1, TPM_MIGRATIONKEYAUTH *outData) { TPM_RESULT res; info("TPM_AuthorizeMigrationKey()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* verify the key size and encryption scheme */ if (migrationKey->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || migrationKey->algorithmParms.algorithmID != TPM_ALG_RSA) return TPM_INAPPROPRIATE_ENC; if (migrationKey->algorithmParms.parms.rsa.keyLength < 2048) return TPM_BAD_KEY_PROPERTY; /* create migration key authorization */ if (tpm_compute_migration_digest(migrationKey, migrateScheme, &tpmData.permanent.data.tpmProof, &outData->digest) != 0) { debug("tpm_compute_migration_digest() failed"); return TPM_FAIL; } outData->migrationScheme = migrateScheme; if (tpm_copy_pubkey(migrationKey, &outData->migrationKey) != 0) { debug("tpm_copy_pubkey() failed"); return TPM_FAIL; } return TPM_SUCCESS; } TPM_RESULT TPM_MigrateKey(TPM_KEY_HANDLE maKeyHandle, TPM_PUBKEY *pubKey, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_PUBKEY_DATA key2; UINT32 size; BYTE *buf; UINT32 buf_len; info("TPM_MigrateKey()"); key = tpm_get_key(maKeyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify key authorization */ res = tpm_verify_auth(auth1, key->usageAuth, maKeyHandle); if (res != TPM_SUCCESS) return res; /* verify key usage */ if (key->keyUsage != TPM_KEY_MIGRATE) return TPM_BAD_KEY_PROPERTY; if (key->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) return TPM_INAPPROPRIATE_ENC; /* verify public key */ if (pubKey->algorithmParms.algorithmID != TPM_ALG_RSA || pubKey->algorithmParms.parms.rsa.keyLength < (inDataSize << 3)) return TPM_BAD_KEY_PROPERTY; if (tpm_setup_pubkey_data(pubKey, &key2) != 0) return TPM_FAIL; /* decrypt inData and re-encrypt it with the public key */ *outDataSize = size = pubKey->algorithmParms.parms.rsa.keyLength >> 3; *outData = tpm_malloc(*outDataSize); buf_len = inDataSize; buf = tpm_malloc(buf_len); if (*outData == NULL || buf == NULL) { free_TPM_PUBKEY_DATA(key2); tpm_free(*outData); tpm_free(buf); return TPM_NOSPACE; } if (tpm_decrypt(key, inData, inDataSize, buf, &buf_len) != 0) { free_TPM_PUBKEY_DATA(key2); tpm_free(*outData); tpm_free(buf); return TPM_DECRYPT_ERROR; } if (tpm_encrypt_public(&key2, buf, buf_len, *outData, outDataSize) != 0) { free_TPM_PUBKEY_DATA(key2); tpm_free(*outData); tpm_free(buf); return TPM_ENCRYPT_ERROR; } free_TPM_PUBKEY_DATA(key2); tpm_free(buf); return TPM_SUCCESS; } TPM_RESULT TPM_CMK_SetRestrictions(TPM_CMK_DELEGATE restriction, TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_CMK_SetRestrictions()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* update delegation restriction */ tpmData.permanent.data.restrictDelegate = restriction; return TPM_SUCCESS; } TPM_RESULT TPM_CMK_ApproveMA(TPM_DIGEST *migrationAuthorityDigest, TPM_AUTH *auth1, TPM_HMAC *outData) { TPM_RESULT res; BYTE buf[2]; tpm_hmac_ctx_t ctx; info("TPM_CMK_ApproveMA()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; /* create hmac of a TPM_CMK_MA_APPROVAL structure */ buf[0] = (TPM_TAG_CMK_MA_APPROVAL >> 8) & 0xff; buf[1] = TPM_TAG_CMK_MA_APPROVAL & 0xff; tpm_hmac_init(&ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&ctx, buf, 2); tpm_hmac_update(&ctx, migrationAuthorityDigest->digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&ctx, outData->digest); return TPM_SUCCESS; } TPM_RESULT TPM_CMK_CreateKey(TPM_KEY_HANDLE parentHandle, TPM_ENCAUTH *dataUsageAuth, TPM_KEY *keyInfo, TPM_HMAC *migrationAuthorityApproval, TPM_DIGEST *migrationAuthorityDigest, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_KEY *wrappedKey) { TPM_RESULT res; TPM_KEY_DATA *parent; TPM_SESSION_DATA *session; tpm_hmac_ctx_t ctx; BYTE buf[SHA1_DIGEST_LENGTH]; TPM_STORE_ASYMKEY store; tpm_rsa_private_key_t rsa; UINT32 key_length; TPM_PUBKEY pubKey; TPM_DIGEST keyDigest; info("TPM_CMK_CreateKey()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify 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_AUTHFAIL; /* must be TPM_KEY12 */ if (keyInfo->tag != TPM_TAG_KEY12) return TPM_INVALID_STRUCTURE; /* verify key parameters */ if (parent->keyUsage != TPM_KEY_STORAGE || parent->encScheme == TPM_ES_NONE || parent->keyFlags & TPM_KEY_FLAG_MIGRATABLE || !(keyInfo->keyFlags & TPM_KEY_FLAG_MIGRATABLE) || !(keyInfo->keyFlags & TPM_KEY_FLAG_AUTHORITY) || keyInfo->keyUsage == TPM_KEY_IDENTITY || keyInfo->keyUsage == TPM_KEY_AUTHCHANGE) return TPM_INVALID_KEYUSAGE; if (keyInfo->algorithmParms.algorithmID != TPM_ALG_RSA || keyInfo->algorithmParms.parmSize == 0 || keyInfo->algorithmParms.parms.rsa.keyLength < 512 || keyInfo->algorithmParms.parms.rsa.numPrimes != 2 || keyInfo->algorithmParms.parms.rsa.exponentSize != 0) return TPM_BAD_KEY_PROPERTY; if (tpmData.permanent.flags.FIPS && (keyInfo->algorithmParms.parms.rsa.keyLength < 1024 || keyInfo->authDataUsage == TPM_AUTH_NEVER || keyInfo->keyUsage == TPM_KEY_LEGACY)) return TPM_NOTFIPS; if ((keyInfo->keyUsage == TPM_KEY_STORAGE || keyInfo->keyUsage == TPM_KEY_MIGRATE) && (keyInfo->algorithmParms.algorithmID != TPM_ALG_RSA || keyInfo->algorithmParms.parms.rsa.keyLength != 2048 || keyInfo->algorithmParms.sigScheme != TPM_SS_NONE || keyInfo->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1)) return TPM_BAD_KEY_PROPERTY; /* verify migration authority */ buf[0] = (TPM_TAG_CMK_MA_APPROVAL >> 8) & 0xff; buf[1] = TPM_TAG_CMK_MA_APPROVAL & 0xff; tpm_hmac_init(&ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&ctx, buf, 2); tpm_hmac_update(&ctx, migrationAuthorityDigest->digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&ctx, buf); if (memcmp(migrationAuthorityApproval->digest, buf, sizeof(TPM_HMAC)) != 0) return TPM_MA_AUTHORITY; /* setup the wrapped key */ memcpy(wrappedKey, keyInfo, sizeof(TPM_KEY)); /* setup key store */ store.payload = TPM_PT_MIGRATE_RESTRICTED; tpm_decrypt_auth_secret(*dataUsageAuth, session->sharedSecret, &session->lastNonceEven, store.usageAuth); /* compute PCR digest */ if (keyInfo->PCRInfoSize > 0) { tpm_compute_pcr_digest(&keyInfo->PCRInfo.creationPCRSelection, &keyInfo->PCRInfo.digestAtCreation, NULL); keyInfo->PCRInfo.localityAtCreation = tpmData.stany.flags.localityModifier; } /* generate key and store it */ key_length = keyInfo->algorithmParms.parms.rsa.keyLength; if (tpm_rsa_generate_key(&rsa, key_length)) { debug("TPM_CreateWrapKey(): tpm_rsa_generate_key() failed."); return TPM_FAIL; } wrappedKey->pubKey.keyLength = key_length >> 3; wrappedKey->pubKey.key = tpm_malloc(wrappedKey->pubKey.keyLength); store.privKey.keyLength = key_length >> 4; store.privKey.key = tpm_malloc(store.privKey.keyLength); wrappedKey->encDataSize = parent->key.size >> 3; wrappedKey->encData = tpm_malloc(wrappedKey->encDataSize); if (wrappedKey->pubKey.key == NULL || store.privKey.key == NULL || wrappedKey->encData == NULL) { tpm_rsa_release_private_key(&rsa); tpm_free(wrappedKey->pubKey.key); tpm_free(store.privKey.key); tpm_free(wrappedKey->encData); return TPM_NOSPACE; } tpm_rsa_export_modulus(&rsa, wrappedKey->pubKey.key, NULL); tpm_rsa_export_prime1(&rsa, store.privKey.key, NULL); tpm_rsa_release_private_key(&rsa); /* create hmac of TPM_CMK_MIGAUTH */ buf[0] = (TPM_TAG_CMK_MIGAUTH >> 8) & 0xff; buf[1] = TPM_TAG_CMK_MIGAUTH & 0xff; memcpy(&pubKey.algorithmParms, &wrappedKey->algorithmParms, sizeof(TPM_KEY_PARMS)); memcpy(&pubKey.pubKey, &wrappedKey->pubKey, sizeof(TPM_STORE_PUBKEY)); if (tpm_compute_pubkey_digest(&pubKey, &keyDigest) !=0 ) { debug("tpm_compute_pubkey_digest() failed"); return TPM_FAIL; } tpm_hmac_init(&ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&ctx, buf, 2); tpm_hmac_update(&ctx, migrationAuthorityDigest->digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&ctx, keyDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&ctx, store.migrationAuth); /* compute the digest of the wrapped key (without encData) */ if (tpm_compute_key_digest(wrappedKey, &store.pubDataDigest)) { debug("TPM_CreateWrapKey(): tpm_compute_key_digest() failed."); return TPM_FAIL; } /* encrypt private key data */ if (tpm_encrypt_private_key(parent, &store, wrappedKey->encData, &wrappedKey->encDataSize)) { tpm_free(wrappedKey->pubKey.key); tpm_free(store.privKey.key); tpm_free(wrappedKey->encData); return TPM_ENCRYPT_ERROR; } tpm_free(store.privKey.key); return TPM_SUCCESS; } TPM_RESULT TPM_CMK_CreateTicket(TPM_PUBKEY *verificationKey, TPM_DIGEST *signedData, UINT32 signatureValueSize, BYTE *signatureValue, TPM_AUTH *auth1, TPM_DIGEST *sigTicket) { TPM_RESULT res; TPM_PUBKEY_DATA key; BYTE buf[2]; TPM_DIGEST keyDigest; tpm_hmac_ctx_t ctx; info("TPM_CMK_CreateTicket()"); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); /* verify key type and algorithm */ if (verificationKey->algorithmParms.algorithmID != TPM_ALG_RSA || verificationKey->algorithmParms.encScheme != TPM_ES_NONE) return TPM_BAD_KEY_PROPERTY; if (verificationKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1 && verificationKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO) return TPM_BAD_KEY_PROPERTY; /* verify signature */ if (tpm_setup_pubkey_data(verificationKey, &key) != 0) return TPM_FAIL; res = tpm_verify(&key, auth1, FALSE, signedData->digest, sizeof(TPM_DIGEST), signatureValue, signatureValueSize); free_TPM_PUBKEY_DATA(key); if (res != TPM_SUCCESS) return res; /* create hmac on TPM_CMK_SIGTICKET */ buf[0] = (TPM_TAG_CMK_SIGTICKET >> 8) & 0xff; buf[1] = TPM_TAG_CMK_SIGTICKET & 0xff; if (tpm_compute_pubkey_digest(verificationKey, &keyDigest) !=0 ) { debug("tpm_compute_pubkey_digest() failed"); return TPM_FAIL; } tpm_hmac_init(&ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&ctx, buf, 2); tpm_hmac_update(&ctx, keyDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&ctx, signedData->digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&ctx, sigTicket->digest); return TPM_SUCCESS; } TPM_RESULT TPM_CMK_CreateBlob(TPM_KEY_HANDLE parentHandle, TPM_MIGRATE_SCHEME migrationType, TPM_MIGRATIONKEYAUTH *migrationKeyAuth, TPM_DIGEST *pubSourceKeyDigest, TPM_MSA_COMPOSITE *msaList, TPM_CMK_AUTH *restrictTicket, TPM_HMAC *sigTicket, UINT32 encDataSize, BYTE *encData, TPM_AUTH *auth1, UINT32 *randomSize, BYTE **random, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *parent; TPM_STORE_ASYMKEY store; BYTE *key_buf; UINT32 key_buf_size; tpm_hmac_ctx_t hmac_ctx; tpm_sha1_ctx_t sha1_ctx; BYTE tag[2], hmac[SHA1_DIGEST_LENGTH]; BYTE *ptr, *buf; UINT32 i, len; size_t buf_len; TPM_DIGEST migKeyDigest; TPM_DIGEST msaListDigest; TPM_DIGEST ticketDigest; TPM_PUBKEY_DATA key; info("TPM_CMK_CreateBlob()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; /* migrationType must match */ if (migrationType != migrationKeyAuth->migrationScheme) return TPM_BAD_MODE; if (parent->keyFlags & TPM_KEY_FLAG_MIGRATABLE) return TPM_BAD_KEY_PROPERTY; /* 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_MIGRATE_RESTRICTED && store.payload != TPM_PT_MIGRATE_EXTERNAL) { tpm_free(key_buf); return TPM_DECRYPT_ERROR; } if (tpm_verify_migration_digest(migrationKeyAuth, &tpmData.permanent.data.tpmProof)) { debug("tpm_verify_migration_digest() failed"); tpm_free(key_buf); return TPM_MIGRATEFAIL; } /* verify the migration authority list */ len = sizeof_TPM_MSA_COMPOSITE((*msaList)); ptr = buf = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_MSA_COMPOSITE(&ptr, &len, msaList)) { debug("tpm_marshal_TPM_MSA_COMPOSITE() failed"); tpm_free(buf); tpm_free(key_buf); return TPM_FAIL; } tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, sizeof_TPM_MSA_COMPOSITE((*msaList))); tpm_sha1_final(&sha1_ctx, msaListDigest.digest); tpm_free(buf); tag[0] = (TPM_TAG_CMK_MIGAUTH >> 8) & 0xff; tag[1] = TPM_TAG_CMK_MIGAUTH & 0xff; tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&hmac_ctx, tag, 2); tpm_hmac_update(&hmac_ctx, msaListDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&hmac_ctx, pubSourceKeyDigest->digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&hmac_ctx, hmac); if (memcmp(hmac, store.migrationAuth, sizeof(TPM_SECRET)) != 0) { tpm_free(key_buf); return TPM_MA_AUTHORITY; } if (tpm_compute_pubkey_digest(&migrationKeyAuth->migrationKey, &migKeyDigest) !=0 ) { debug("tpm_compute_pubkey_digest() failed"); tpm_free(key_buf); return TPM_FAIL; } len = sizeof_TPM_CMK_AUTH((*restrictTicket)); ptr = buf = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_CMK_AUTH(&ptr, &len, restrictTicket)) { debug("tpm_marshal_TPM_CMK_AUTH() failed"); tpm_free(buf); tpm_free(key_buf); return TPM_FAIL; } tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf, sizeof_TPM_CMK_AUTH((*restrictTicket))); tpm_sha1_final(&sha1_ctx, ticketDigest.digest); tpm_free(buf); /* verify the migration destination */ if (migrationKeyAuth->migrationScheme == TPM_MS_RESTRICT_MIGRATE) { for (i = 0; i < msaList->MSAlist; i++) { if (memcmp(msaList->migAuthDigest[i].digest, migKeyDigest.digest, sizeof(TPM_DIGEST)) == 0) break; } if (i >= msaList->MSAlist) { tpm_free(key_buf); return TPM_MA_AUTHORITY; } /* verify the key type and algorithm */ if (migrationKeyAuth->migrationKey.algorithmParms.algorithmID != TPM_ALG_RSA || migrationKeyAuth->migrationKey.algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || migrationKeyAuth->migrationKey.algorithmParms.sigScheme != TPM_SS_NONE) { tpm_free(key_buf); return TPM_BAD_KEY_PROPERTY; } } else if (migrationKeyAuth->migrationScheme == TPM_MS_RESTRICT_APPROVE) { if (restrictTicket == NULL || sigTicket == NULL) { tpm_free(key_buf); return TPM_BAD_PARAMETER; } for (i = 0; i < msaList->MSAlist; i++) { /* create hmac of TPM_CMK_SIGTICKET */ tag[0] = (TPM_TAG_CMK_SIGTICKET >> 8) & 0xff; tag[1] = TPM_TAG_CMK_SIGTICKET & 0xff; tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&hmac_ctx, tag, 2); tpm_hmac_update(&hmac_ctx, msaList->migAuthDigest[i].digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&hmac_ctx, ticketDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&hmac_ctx, hmac); if (memcmp(hmac, sigTicket->digest, sizeof(TPM_DIGEST)) == 0) break; } if (i >= msaList->MSAlist) { tpm_free(key_buf); return TPM_MA_AUTHORITY; } if (memcmp(&restrictTicket->destinationKeyDigest, &migKeyDigest, sizeof(TPM_DIGEST)) != 0) { tpm_free(key_buf); return TPM_MA_DESTINATION; } if (memcmp(&restrictTicket->sourceKeyDigest, pubSourceKeyDigest, sizeof(TPM_DIGEST)) != 0) { tpm_free(key_buf); return TPM_MA_SOURCE; } } else { tpm_free(key_buf); return TPM_BAD_PARAMETER; } /* set public key */ if (tpm_setup_pubkey_data(&migrationKeyAuth->migrationKey, &key) != 0) { debug("tpm_setup_pubkey() failed"); tpm_free(key_buf); return TPM_FAIL; } /* generate an OAEP encoding of the TPM_MIGRATE_ASYMKEY structure: 0x00|seed|K1|0x00-pad|0x01|TPM_MIGRATE_ASYMKEY */ len = buf_len = 198; ptr = buf = tpm_malloc(buf_len); *randomSize = buf_len; *random = tpm_malloc(*randomSize); *outDataSize = key.key.size >> 3; *outData = tpm_malloc(*outDataSize); if (buf == NULL || *random == NULL || *outData == NULL) { free_TPM_PUBKEY_DATA(key); tpm_free(buf); tpm_free(*random); tpm_free(*outData); tpm_free(key_buf); return TPM_NOSPACE; } memset(buf, 0, buf_len); tpm_marshal_UINT32(&ptr, &len, store.privKey.keyLength); memcpy(ptr, store.privKey.key, 16); ptr += 16; tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, msaListDigest.digest, sizeof(TPM_DIGEST)); tpm_sha1_update(&sha1_ctx, pubSourceKeyDigest->digest, sizeof(TPM_DIGEST)); tpm_sha1_final(&sha1_ctx, ptr); len = 46 + store.privKey.keyLength - 16; ptr = &buf[buf_len - len]; tpm_marshal_BYTE(&ptr, &len, 0x01); tpm_marshal_TPM_PAYLOAD_TYPE(&ptr, &len, TPM_PT_CMK_MIGRATE); tpm_marshal_TPM_SECRET(&ptr, &len, &store.usageAuth); tpm_marshal_TPM_DIGEST(&ptr, &len, &store.pubDataDigest); tpm_marshal_UINT32(&ptr, &len, store.privKey.keyLength - 16); memcpy(ptr, &store.privKey.key[16], store.privKey.keyLength - 16); tpm_rsa_mask_generation(buf, SHA1_DIGEST_LENGTH, &buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH); tpm_rsa_mask_generation(&buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH, buf, SHA1_DIGEST_LENGTH); /* XOR encrypt OAEP encoding */ tpm_get_random_bytes(*random, *randomSize); for (len = 0; len < buf_len; len++) buf[len] ^= (*random)[len]; /* RSA encrypt OAEP encoding */ if (tpm_rsa_encrypt(&key.key, RSA_ES_OAEP_SHA1, buf, buf_len, *outData, &buf_len)) { debug("tpm_rsa_encrypt() failed"); free_TPM_PUBKEY_DATA(key); tpm_free(buf); tpm_free(*random); tpm_free(*outData); tpm_free(key_buf); return TPM_ENCRYPT_ERROR; } *outDataSize = buf_len; free_TPM_PUBKEY_DATA(key); tpm_free(key_buf); tpm_free(buf); return TPM_SUCCESS; } TPM_RESULT TPM_CMK_ConvertMigration(TPM_KEY_HANDLE parentHandle, TPM_CMK_AUTH *restrictTicket, TPM_HMAC *sigTicket, TPM_KEY *migratedKey, TPM_MSA_COMPOSITE *msaList, UINT32 randomSize, BYTE *random, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *parent; BYTE *ptr, *buf, *buf2; UINT32 i, len; size_t buf_len; BYTE tag[2], hmac[SHA1_DIGEST_LENGTH]; TPM_STORE_ASYMKEY store; tpm_sha1_ctx_t sha1_ctx; tpm_hmac_ctx_t hmac_ctx; TPM_PUBKEY migratedPubKey; TPM_PUBKEY parentPubKey; TPM_DIGEST migKeyDigest; TPM_DIGEST msaListDigest; TPM_DIGEST ticketDigest; TPM_DIGEST parentDigest; info("TPM_CMK_ConvertMigration()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || parent->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; } /* verify key properties */ if (parent->keyUsage != TPM_KEY_STORAGE || parent->keyFlags & TPM_KEY_FLAG_MIGRATABLE) return TPM_INVALID_KEYUSAGE; if (!(migratedKey->keyFlags & TPM_KEY_FLAG_MIGRATABLE) && (!(migratedKey->keyFlags & TPM_KEY_FLAG_AUTHORITY))) return TPM_INVALID_KEYUSAGE; /* decrypt private key */ buf_len = parent->key.size >> 3; buf = tpm_malloc(buf_len); if (buf == NULL) return TPM_NOSPACE; /* RSA decrypt OAEP encoding */ if (tpm_rsa_decrypt(&parent->key, RSA_ES_OAEP_SHA1, migratedKey->encData, migratedKey->encDataSize, buf, &buf_len) || buf_len != randomSize || buf_len != 198) { debug("tpm_rsa_decrypt() failed"); tpm_free(buf); return TPM_DECRYPT_ERROR; } /* XOR decrypt OAEP encoding */ for (len = 0; len < buf_len; len++) buf[len] ^= random[len]; /* unmask OAEP encoding */ tpm_rsa_mask_generation(&buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH , buf, SHA1_DIGEST_LENGTH); tpm_rsa_mask_generation(buf, SHA1_DIGEST_LENGTH, &buf[SHA1_DIGEST_LENGTH], buf_len - SHA1_DIGEST_LENGTH); /* compute digest of migrated public key */ memcpy(&migratedPubKey.algorithmParms, &migratedKey->algorithmParms, sizeof(TPM_KEY_PARMS)); memcpy(&migratedPubKey.pubKey, &migratedKey->pubKey, sizeof(TPM_STORE_PUBKEY)); if (tpm_compute_pubkey_digest(&migratedPubKey, &migKeyDigest) != 0) { debug("tpm_compute_pubkey_digest() failed"); tpm_free(buf); return TPM_FAIL; } /* compute digest of parent key */ parentPubKey.pubKey.keyLength = parent->key.size >> 3; parentPubKey.pubKey.key = tpm_malloc(parentPubKey.pubKey.keyLength); if (parentPubKey.pubKey.key == NULL) { tpm_free(buf); return TPM_NOSPACE; } tpm_rsa_export_modulus(&parent->key, parentPubKey.pubKey.key, NULL); if (tpm_setup_key_parms(parent, &parentPubKey.algorithmParms) != 0) { debug("tpm_setup_key_parms() failed."); tpm_free(parentPubKey.pubKey.key); tpm_free(buf); return TPM_FAIL; } if (tpm_compute_pubkey_digest(&parentPubKey, &parentDigest) != 0) { debug("tpm_compute_pubkey_digest() failed."); free_TPM_PUBKEY(parentPubKey); tpm_free(buf); return TPM_FAIL; } free_TPM_PUBKEY(parentPubKey); /* compute digest of msaList */ len = sizeof_TPM_MSA_COMPOSITE((*msaList)); ptr = buf2 = tpm_malloc(len); if (buf2 == NULL || tpm_marshal_TPM_MSA_COMPOSITE(&ptr, &len, msaList)) { debug("tpm_marshal_TPM_MSA_COMPOSITE() failed"); tpm_free(buf2); tpm_free(buf); return TPM_FAIL; } tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf2, sizeof_TPM_MSA_COMPOSITE((*msaList))); tpm_sha1_final(&sha1_ctx, msaListDigest.digest); tpm_free(buf2); /* compute digest of restrictedTicket */ len = sizeof_TPM_CMK_AUTH((*restrictTicket)); ptr = buf2 = tpm_malloc(len); if (buf2 == NULL || tpm_marshal_TPM_CMK_AUTH(&ptr, &len, restrictTicket)) { debug("tpm_marshal_TPM_CMK_AUTH() failed"); tpm_free(buf2); tpm_free(buf); return TPM_FAIL; } tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, buf2, sizeof_TPM_CMK_AUTH((*restrictTicket))); tpm_sha1_final(&sha1_ctx, ticketDigest.digest); tpm_free(buf2); /* verify decoded data */ tpm_sha1_init(&sha1_ctx); tpm_sha1_update(&sha1_ctx, msaListDigest.digest, sizeof(TPM_DIGEST)); tpm_sha1_update(&sha1_ctx, migKeyDigest.digest, sizeof(TPM_DIGEST)); tpm_sha1_final(&sha1_ctx, hmac); if (memcmp(&buf[20], hmac, sizeof(TPM_DIGEST)) != 0) { tpm_free(buf); return TPM_INVALID_STRUCTURE; } /* create a TPM_STORE_ASYMKEY structure */ for (ptr = &buf[40]; *ptr == 0x00; ptr++); if (ptr[0] != 0x01 || ptr[1] != TPM_PT_CMK_MIGRATE) { debug("OAEP encoding is invalid"); tpm_free(buf); return TPM_DECRYPT_ERROR; } ptr += 2; len = buf_len - (ptr - buf); store.payload = TPM_PT_MIGRATE_EXTERNAL; tpm_unmarshal_TPM_SECRET(&ptr, &len, &store.usageAuth); tpm_unmarshal_TPM_DIGEST(&ptr, &len, &store.pubDataDigest); tpm_unmarshal_UINT32(&ptr, &len, &store.privKey.keyLength); store.privKey.keyLength += 16; if (store.privKey.keyLength != len + 16) { error("invalid key length %d; expected %d", store.privKey.keyLength, len + 16); tpm_free(buf); return TPM_DECRYPT_ERROR; } memmove(&buf[20], ptr, len); store.privKey.key = &buf[4]; tag[0] = (TPM_TAG_CMK_MIGAUTH >> 8) & 0xff; tag[1] = TPM_TAG_CMK_MIGAUTH & 0xff; tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&hmac_ctx, tag, 2); tpm_hmac_update(&hmac_ctx, msaListDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&hmac_ctx, migKeyDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&hmac_ctx, store.migrationAuth); /* verify the migration destination */ for (i = 0; i < msaList->MSAlist; i++) { /* create hmac of TPM_CMK_SIGTICKET */ tag[0] = (TPM_TAG_CMK_SIGTICKET >> 8) & 0xff; tag[1] = TPM_TAG_CMK_SIGTICKET & 0xff; tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE)); tpm_hmac_update(&hmac_ctx, tag, 2); tpm_hmac_update(&hmac_ctx, msaList->migAuthDigest[i].digest, sizeof(TPM_DIGEST)); tpm_hmac_update(&hmac_ctx, ticketDigest.digest, sizeof(TPM_DIGEST)); tpm_hmac_final(&hmac_ctx, hmac); if (memcmp(hmac, sigTicket->digest, sizeof(TPM_DIGEST)) == 0) break; } if (i >= msaList->MSAlist) { tpm_free(buf); return TPM_MA_AUTHORITY; } if (memcmp(&restrictTicket->destinationKeyDigest, &parentDigest, sizeof(TPM_DIGEST)) != 0) { tpm_free(buf); return TPM_MA_DESTINATION; } if (memcmp(&restrictTicket->sourceKeyDigest, &migKeyDigest, sizeof(TPM_DIGEST)) != 0) { tpm_free(buf); return TPM_MA_SOURCE; } /* encrypt private key */ *outDataSize = parent->key.size >> 3; *outData = tpm_malloc(*outDataSize); if (*outData == NULL) { tpm_free(buf); return TPM_NOSPACE; } if (tpm_encrypt_private_key(parent, &store, *outData, outDataSize)) { debug("tpm_encrypt_private_key() failed"); tpm_free(*outData); tpm_free(buf); return TPM_ENCRYPT_ERROR; } tpm_free(buf); return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_nv_storage.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_nv_storage.c 465 2011-07-19 17:20:32Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" /* * Non-volatile Storage ([TPM_Part3], Section 20) * This section handles the allocation and use of the TPM non-volatile storage. */ TPM_NV_DATA_SENSITIVE *tpm_get_nvs(TPM_NV_INDEX index) { int i; for (i = 0; i < TPM_MAX_NVS; i++) { if (tpmData.permanent.data.nvStorage[i].valid && tpmData.permanent.data.nvStorage[i].pubInfo.nvIndex == index) { return &tpmData.permanent.data.nvStorage[i]; } } return NULL; } static TPM_NV_DATA_SENSITIVE *tpm_get_free_nvs(void) { int i; for (i = 0; i < TPM_MAX_NVS; i++) { if (!tpmData.permanent.data.nvStorage[i].valid) { return &tpmData.permanent.data.nvStorage[i]; } } return NULL; } void tpm_nv_remove_data(TPM_NV_DATA_SENSITIVE *nv) { UINT32 i; /* remove data */ memcpy(tpmData.permanent.data.nvData + nv->dataIndex, tpmData.permanent.data.nvData + nv->dataIndex + nv->pubInfo.dataSize, nv->pubInfo.dataSize); /* adapt indices */ for (i = 0; i < TPM_MAX_NVS; i++) { if (tpmData.permanent.data.nvStorage[i].valid && tpmData.permanent.data.nvStorage[i].dataIndex > nv->dataIndex) tpmData.permanent.data.nvStorage[i].dataIndex -= nv->pubInfo.dataSize; } tpmData.permanent.data.nvDataSize -= nv->pubInfo.dataSize; /* invalidate meta data */ memset(tpmData.permanent.data.nvData + tpmData.permanent.data.nvDataSize, 0xff, nv->pubInfo.dataSize); memset(nv, 0x00, sizeof(TPM_NV_DATA_SENSITIVE)); } TPM_RESULT TPM_NV_DefineSpace(TPM_NV_DATA_PUBLIC *pubInfo, TPM_ENCAUTH *encAuth, TPM_AUTH *auth1) { TPM_RESULT res; TPM_SECRET plainAuth; TPM_NV_DATA_SENSITIVE *nv; TPM_SESSION_DATA *session = NULL; UINT32 i; info("TPM_NV_DefineSpace()"); /* lock NV storage */ if (auth1->authHandle == TPM_INVALID_HANDLE && pubInfo->nvIndex == TPM_NV_INDEX_LOCK) { debug("nvIndex = TPM_NV_INDEX_LOCK"); tpmData.permanent.flags.nvLocked = TRUE; return TPM_SUCCESS; } debug("nvIndex = %08x", pubInfo->nvIndex); /* verify maximal number of writes without an owner */ if (!tpmData.permanent.flags.owned && ++tpmData.permanent.data.noOwnerNVWrite > TPM_MAX_NV_WRITE_NOOWNER) return TPM_MAXNVWRITES; /* if NV storage is not locked omit authorization verifications */ if (tpmData.permanent.flags.nvLocked) { if (auth1->authHandle == TPM_INVALID_HANDLE) { /* no authorization available */ if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; if (tpmData.permanent.flags.owned) return TPM_OWNER_SET; if (pubInfo->dataSize == 0) return TPM_BAD_DATASIZE; memcpy(plainAuth, *encAuth, sizeof(TPM_SECRET)); } else { /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; session = tpm_get_auth(auth1->authHandle); if (session->type != TPM_ST_OSAP) return TPM_AUTHFAIL; auth1->continueAuthSession = FALSE; /* decrypt auth */ tpm_decrypt_auth_secret(*encAuth, session->sharedSecret, &session->lastNonceEven, plainAuth); } if (pubInfo->nvIndex & TPM_NV_INDEX_D) return TPM_BADINDEX; } /* check whether nvIndex is reserved */ if (pubInfo->nvIndex == TPM_NV_INDEX0 || pubInfo->nvIndex == TPM_NV_INDEX_DIR) return TPM_BADINDEX; /* check whether nvIndex points to a valid NV storage area */ nv = tpm_get_nvs(pubInfo->nvIndex); if (nv != NULL) { if (tpmData.permanent.flags.nvLocked) { if ((nv->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && tpmData.stclear.flags.bGlobalLock) return TPM_AREA_LOCKED; if ((nv->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && nv->pubInfo.bWriteSTClear) return TPM_AREA_LOCKED; } debug("deleting NV storage area for index %08x", pubInfo->nvIndex); /* invalidate all associated sessions but the current one */ for (i = 0; i < TPM_MAX_SESSIONS; i++) { if (tpmData.stany.data.sessions[i].handle == pubInfo->nvIndex && &tpmData.stany.data.sessions[i] != session) { memset(&tpmData.stany.data.sessions[i], 0, sizeof(TPM_SESSION_DATA)); } } /* delete the NV storage area */ tpm_nv_remove_data(nv); if (pubInfo->dataSize == 0) return TPM_SUCCESS; } /* verify pcrInfoRead and pcrInfoWrite */ if (pubInfo->pcrInfoRead.pcrSelection.sizeOfSelect > TPM_NUM_PCR/8 || (pubInfo->pcrInfoRead.localityAtRelease & 0x1f) == 0 || (pubInfo->pcrInfoRead.localityAtRelease & 0xe0) != 0 || pubInfo->pcrInfoWrite.pcrSelection.sizeOfSelect > TPM_NUM_PCR/8 || (pubInfo->pcrInfoWrite.localityAtRelease & 0x1f) == 0 || (pubInfo->pcrInfoWrite.localityAtRelease & 0xe0) != 0) return TPM_INVALID_STRUCTURE; /* verify that attributes are consistent */ if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && (pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE)) return TPM_AUTH_CONFLICT; if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERREAD) && (pubInfo->permission.attributes & TPM_NV_PER_AUTHREAD)) return TPM_AUTH_CONFLICT; if (!(pubInfo->permission.attributes & (TPM_NV_PER_OWNERWRITE | TPM_NV_PER_AUTHWRITE | TPM_NV_PER_WRITEDEFINE | TPM_NV_PER_PPWRITE)) && pubInfo->pcrInfoWrite.localityAtRelease == 0x1f) return TPM_PER_NOWRITE; if (pubInfo->dataSize == 0) return TPM_BAD_PARAM_SIZE; /* check whether there is enough space for the new NV storage area */ nv = tpm_get_free_nvs(); if (pubInfo->dataSize > (TPM_MAX_NV_SIZE - tpmData.permanent.data.nvDataSize) || nv == NULL) return TPM_NOSPACE; /* return success if this was just a test */ if (pubInfo->nvIndex == TPM_NV_INDEX_TRIAL) return TPM_SUCCESS; /* allocate and initialize a new NV storage area */ nv->tag = TPM_TAG_NV_DATA_SENSITIVE; memcpy(&nv->pubInfo, pubInfo, sizeof(TPM_NV_DATA_PUBLIC)); nv->pubInfo.bReadSTClear = FALSE; nv->pubInfo.bWriteSTClear = FALSE; nv->pubInfo.bWriteDefine = FALSE; memcpy(nv->authValue, plainAuth, sizeof(TPM_SECRET)); nv->dataIndex = tpmData.permanent.data.nvDataSize; tpmData.permanent.data.nvDataSize += pubInfo->dataSize; nv->valid = TRUE; memset(tpmData.permanent.data.nvData + nv->dataIndex, 0xff, pubInfo->dataSize); return TPM_SUCCESS; } static TPM_RESULT nv_write(TPM_NV_DATA_SENSITIVE *nv, UINT32 offset, UINT32 dataSize, BYTE *data, BOOL verify) { TPM_RESULT res; TPM_DIGEST digest; if (verify) { /* test for physical presence if required */ if ((nv->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) && !tpm_get_physical_presence()) return TPM_BAD_PRESENCE; /* verify that area is not locked */ if ((nv->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && nv->pubInfo.bWriteDefine) return TPM_AREA_LOCKED; if ((nv->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && tpmData.stclear.flags.bGlobalLock) return TPM_AREA_LOCKED; if ((nv->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && nv->pubInfo.bWriteSTClear) return TPM_AREA_LOCKED; /* verify locality and PCRs */ if (!(nv->pubInfo.pcrInfoWrite.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; res = tpm_compute_pcr_digest(&nv->pubInfo.pcrInfoWrite.pcrSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &nv->pubInfo.pcrInfoWrite.digestAtRelease, sizeof(TPM_DIGEST))) return TPM_WRONGPCRVAL; } /* write data */ if (dataSize == 0) { nv->pubInfo.bWriteSTClear = TRUE; nv->pubInfo.bWriteDefine = TRUE; } else { if (offset + dataSize > nv->pubInfo.dataSize) return TPM_NOSPACE; if ((nv->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && dataSize != nv->pubInfo.dataSize) return TPM_NOT_FULLWRITE; memcpy(tpmData.permanent.data.nvData + nv->dataIndex + offset, data, dataSize); } nv->pubInfo.bReadSTClear = FALSE; return TPM_SUCCESS; } TPM_RESULT TPM_NV_WriteValue(TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 dataSize, BYTE *data, TPM_AUTH *auth1) { TPM_RESULT res; TPM_NV_DATA_SENSITIVE *nv; info("TPM_NV_WriteValue()"); /* set global lock */ if (nvIndex == TPM_NV_INDEX0) { debug("nvIndex = TPM_NV_INDEX0"); tpmData.stclear.flags.bGlobalLock = TRUE; return TPM_SUCCESS; } debug("nvIndex = %08x, offset = %d, dataSize = %d", nvIndex, offset, dataSize); /* get NV storage area that nvIndex points to */ nv = tpm_get_nvs(nvIndex); if (nv == NULL) return TPM_BADINDEX; if (nv->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE) return TPM_AUTH_CONFLICT; /* if NV storage is not locked omit authorization verifications */ if (tpmData.permanent.flags.nvLocked) { if (auth1->authHandle == TPM_INVALID_HANDLE) { /* no authorization available */ if (nv->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE) return TPM_AUTH_CONFLICT; if (++tpmData.permanent.data.noOwnerNVWrite > TPM_MAX_NV_WRITE_NOOWNER) return TPM_MAXNVWRITES; } else { /* verify authorization */ if (!(nv->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) return TPM_AUTH_CONFLICT; res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; } } /* write data */ return nv_write(nv, offset, dataSize, data, tpmData.permanent.flags.nvLocked); } TPM_RESULT TPM_NV_WriteValueAuth(TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 dataSize, BYTE *data, TPM_AUTH *auth1) { TPM_RESULT res; TPM_NV_DATA_SENSITIVE *nv; info("TPM_NV_WriteValueAuth()"); debug("nvIndex = %08x, offset = %d, dataSize = %d", nvIndex, offset, dataSize); /* get NV storage area that nvIndex points to */ nv = tpm_get_nvs(nvIndex); if (nv == NULL) return TPM_BADINDEX; if (!(nv->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE)) return TPM_AUTH_CONFLICT; /* verify authorization */ res = tpm_verify_auth(auth1, nv->authValue, nvIndex); if (res != TPM_SUCCESS) return res; /* write data */ return nv_write(nv, offset, dataSize, data, TRUE); } TPM_RESULT nv_read(TPM_NV_DATA_SENSITIVE *nv, UINT32 offset, UINT32 inDataSize, UINT32 *outDataSize, BYTE **data, BOOL verify) { TPM_RESULT res; TPM_DIGEST digest; if (verify) { /* test for physical presence if required */ if ((nv->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) && !tpm_get_physical_presence()) return TPM_BAD_PRESENCE; /* verify that area is not locked */ if ((nv->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && nv->pubInfo.bReadSTClear) return TPM_DISABLED_CMD; /* verify locality and PCRs */ if (!(nv->pubInfo.pcrInfoRead.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; res = tpm_compute_pcr_digest(&nv->pubInfo.pcrInfoRead.pcrSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &nv->pubInfo.pcrInfoRead.digestAtRelease, sizeof(TPM_DIGEST))) return TPM_WRONGPCRVAL; } /* read data */ if (inDataSize == 0) { nv->pubInfo.bReadSTClear = TRUE; *outDataSize = 0; *data = NULL; } else { if (offset + inDataSize > nv->pubInfo.dataSize) return TPM_NOSPACE; *outDataSize = inDataSize; *data = tpm_malloc(*outDataSize); if (*data == NULL) return TPM_FAIL; memcpy(*data, tpmData.permanent.data.nvData + nv->dataIndex + offset, inDataSize); } return TPM_SUCCESS; } TPM_RESULT TPM_NV_ReadValue(TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 inDataSize, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **data) { TPM_RESULT res; TPM_NV_DATA_SENSITIVE *nv; info("TPM_NV_ReadValue()"); debug("nvIndex = %08x, offset = %d, inDataSize = %d", nvIndex, offset, inDataSize); /* get NV storage area that nvIndex points to */ nv = tpm_get_nvs(nvIndex); if (nv == NULL) return TPM_BADINDEX; if (nv->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD) return TPM_AUTH_CONFLICT; /* if NV storage is not locked omit authorization verifications */ if (tpmData.permanent.flags.nvLocked) { if (auth1->authHandle == TPM_INVALID_HANDLE) { /* no authorization available */ if (nv->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) return TPM_AUTH_CONFLICT; } else { /* verify authorization */ if (!(nv->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) return TPM_AUTH_CONFLICT; res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; } } /* read data */ return nv_read(nv, offset, inDataSize, outDataSize, data, TRUE); } TPM_RESULT TPM_NV_ReadValueAuth(TPM_NV_INDEX nvIndex, UINT32 offset, UINT32 inDataSize, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **data) { TPM_RESULT res; TPM_NV_DATA_SENSITIVE *nv; info("TPM_NV_ReadValueAuth()"); debug("nvIndex = %08x, offset = %d, inDataSize = %d", nvIndex, offset, inDataSize); /* get NV storage area that nvIndex points to */ nv = tpm_get_nvs(nvIndex); if (nv == NULL) return TPM_BADINDEX; if (!(nv->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD)) return TPM_AUTH_CONFLICT; /* verify authorization */ res = tpm_verify_auth(auth1, nv->authValue, nvIndex); if (res != TPM_SUCCESS) return res; /* read data */ return nv_read(nv, offset, inDataSize, outDataSize, data, TRUE); } ================================================ FILE: tpm/tpm_owner.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_owner.c 470 2011-10-25 12:02:49Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "crypto/rsa.h" /* * Admin Opt-in ([TPM_Part3], Section 5) * [tpm_owner.c] */ TPM_RESULT TPM_SetOwnerInstall(BOOL state) { info("TPM_SetOwnerInstall()"); if (tpmData.permanent.flags.owned) return TPM_SUCCESS; if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; tpmData.permanent.flags.ownership = state; return TPM_SUCCESS; } TPM_RESULT TPM_OwnerSetDisable(BOOL disableState, TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_OwnerSetDisable()"); res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; tpmData.permanent.flags.disable = disableState; return TPM_SUCCESS; } TPM_RESULT TPM_PhysicalEnable() { info("TPM_PhysicalEnable()"); if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; tpmData.permanent.flags.disable = FALSE; return TPM_SUCCESS; } TPM_RESULT TPM_PhysicalDisable() { info("TPM_PhysicalDisable()"); if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; tpmData.permanent.flags.disable = TRUE; return TPM_SUCCESS; } TPM_RESULT TPM_PhysicalSetDeactivated(BOOL state) { info("TPM_PhysicalSetDeactivated()"); if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; tpmData.permanent.flags.deactivated = state; return TPM_SUCCESS; } TPM_RESULT TPM_SetTempDeactivated(TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_SetTempDeactivated()"); if (auth1->authHandle == TPM_INVALID_HANDLE) { if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; } else { if (!tpmData.permanent.flags.operator) return TPM_NOOPERATOR; res = tpm_verify_auth(auth1, tpmData.permanent.data.operatorAuth, TPM_KH_OPERATOR); if (res != TPM_SUCCESS) return res; } tpmData.stclear.flags.deactivated = TRUE; return TPM_SUCCESS; } TPM_RESULT TPM_SetOperatorAuth(TPM_SECRET *operatorAuth) { info("TPM_SetOperatorAuth()"); if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; memcpy(&tpmData.permanent.data.operatorAuth, operatorAuth, sizeof(TPM_SECRET)); tpmData.permanent.flags.operator = TRUE; return TPM_SUCCESS; } /* * Admin Ownership ([TPM_Part3], Section 6) */ TPM_RESULT TPM_TakeOwnership(TPM_PROTOCOL_ID protocolID, UINT32 encOwnerAuthSize, BYTE *encOwnerAuth, UINT32 encSrkAuthSize, BYTE *encSrkAuth, TPM_KEY *srkParams, TPM_AUTH *auth1, TPM_KEY *srkPub) { TPM_RESULT res; tpm_rsa_private_key_t *ek = &tpmData.permanent.data.endorsementKey; TPM_KEY_DATA *srk = &tpmData.permanent.data.srk; size_t buf_size = ek->size >> 3; BYTE buf[buf_size]; info("TPM_TakeOwnership()"); if (!ek->size) return TPM_NO_ENDORSEMENT; if (protocolID != TPM_PID_OWNER) return TPM_BAD_PARAMETER; if (tpmData.permanent.flags.owned) return TPM_OWNER_SET; if (!tpmData.permanent.flags.ownership) return TPM_INSTALL_DISABLED; /* decrypt ownerAuth */ if (tpm_rsa_decrypt(ek, RSA_ES_OAEP_SHA1, encOwnerAuth, encOwnerAuthSize, buf, &buf_size) != 0) return TPM_DECRYPT_ERROR; if (buf_size != sizeof(TPM_SECRET)) return TPM_BAD_KEY_PROPERTY; memcpy(tpmData.permanent.data.ownerAuth, buf, buf_size); /* verify authorization */ res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (tpm_get_auth(auth1->authHandle)->type != TPM_ST_OIAP) return TPM_AUTHFAIL; /* reset srk and decrypt srkAuth */ memset(srk, 0, sizeof(*srk)); if (tpm_rsa_decrypt(ek, RSA_ES_OAEP_SHA1, encSrkAuth, encSrkAuthSize, buf, &buf_size) != 0) return TPM_DECRYPT_ERROR; if (buf_size != sizeof(TPM_SECRET)) return TPM_BAD_KEY_PROPERTY; memcpy(srk->usageAuth, buf, buf_size); /* validate SRK parameters */ if (srkParams->keyFlags & TPM_KEY_FLAG_MIGRATABLE || srkParams->keyUsage != TPM_KEY_STORAGE) return TPM_INVALID_KEYUSAGE; if (srkParams->algorithmParms.algorithmID != TPM_ALG_RSA || srkParams->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1 || srkParams->algorithmParms.sigScheme != TPM_SS_NONE || srkParams->algorithmParms.parmSize == 0 || srkParams->algorithmParms.parms.rsa.keyLength != 2048 || srkParams->algorithmParms.parms.rsa.numPrimes != 2 || srkParams->algorithmParms.parms.rsa.exponentSize != 0 || srkParams->PCRInfoSize != 0) return TPM_BAD_KEY_PROPERTY; /* setup and generate SRK */ srk->keyFlags = srkParams->keyFlags; srk->keyFlags |= TPM_KEY_FLAG_PCR_IGNORE; srk->keyFlags &= ~TPM_KEY_FLAG_HAS_PCR; srk->keyUsage = srkParams->keyUsage; srk->encScheme = srkParams->algorithmParms.encScheme; srk->sigScheme = srkParams->algorithmParms.sigScheme; srk->authDataUsage = srkParams->authDataUsage; debug("srk->authDataUsage = %02x", srk->authDataUsage); srk->parentPCRStatus = FALSE; srkParams->algorithmParms.parms.rsa.keyLength = 2048; if (tpm_rsa_generate_key(&srk->key, srkParams->algorithmParms.parms.rsa.keyLength)) return TPM_FAIL; srk->payload = TPM_PT_ASYM; /* generate context, delegate, and DAA key */ tpm_get_random_bytes(tpmData.permanent.data.contextKey, sizeof(tpmData.permanent.data.contextKey)); tpm_get_random_bytes(tpmData.permanent.data.delegateKey, sizeof(tpmData.permanent.data.delegateKey)); tpm_get_random_bytes(tpmData.permanent.data.daaKey, sizeof(tpmData.permanent.data.daaKey)); /* export SRK */ memcpy(srkPub, srkParams, sizeof(TPM_KEY)); srkPub->pubKey.keyLength = srk->key.size >> 3; srkPub->pubKey.key = tpm_malloc(srkPub->pubKey.keyLength); if (srkPub->pubKey.key == NULL) { tpm_rsa_release_private_key(&srk->key); srk->payload = TPM_PT_NONE; return TPM_FAIL; } tpm_rsa_export_modulus(&srk->key, srkPub->pubKey.key, NULL); /* setup tpmProof/daaProof and set state to owned */ tpm_get_random_bytes(tpmData.permanent.data.tpmProof.nonce, sizeof(tpmData.permanent.data.tpmProof.nonce)); tpm_get_random_bytes(tpmData.permanent.data.daaProof.nonce, sizeof(tpmData.permanent.data.daaProof.nonce)); tpmData.permanent.flags.readPubek = FALSE; tpmData.permanent.flags.owned = TRUE; return TPM_SUCCESS; } void tpm_owner_clear() { int i; /* unload all keys */ for (i = 0; i < TPM_MAX_KEYS; i++) { if (tpmData.permanent.data.keys[i].payload) TPM_FlushSpecific(INDEX_TO_KEY_HANDLE(i), TPM_RT_KEY); } /* invalidate stany and stclear data */ memset(&tpmData.stany.data, 0 , sizeof(tpmData.stany.data)); memset(&tpmData.stclear.data, 0 , sizeof(tpmData.stclear.data)); /* release SRK */ tpm_rsa_release_private_key(&tpmData.permanent.data.srk.key); /* invalidate permanent data */ memset(&tpmData.permanent.data.ownerAuth, 0, sizeof(tpmData.permanent.data.ownerAuth)); memset(&tpmData.permanent.data.srk, 0, sizeof(tpmData.permanent.data.srk)); memset(&tpmData.permanent.data.tpmProof, 0, sizeof(tpmData.permanent.data.tpmProof)); memset(&tpmData.permanent.data.operatorAuth, 0, sizeof(tpmData.permanent.data.operatorAuth)); /* invalidate delegate, context, and DAA key */ memset(&tpmData.permanent.data.contextKey, 0, sizeof(tpmData.permanent.data.contextKey)); memset(&tpmData.permanent.data.delegateKey, 0, sizeof(tpmData.permanent.data.delegateKey)); /* set permanent data */ tpmData.permanent.data.noOwnerNVWrite = 0; tpmData.permanent.data.restrictDelegate = 0; memset (tpmData.permanent.data.ordinalAuditStatus, 0, sizeof(tpmData.permanent.data.ordinalAuditStatus)); /* set permanent flags */ tpmData.permanent.flags.owned = FALSE; tpmData.permanent.flags.operator = FALSE; tpmData.permanent.flags.disableOwnerClear = FALSE; tpmData.permanent.flags.ownership = TRUE; tpmData.permanent.flags.disable = FALSE; tpmData.permanent.flags.deactivated = FALSE; tpmData.permanent.flags.maintenanceDone = FALSE; tpmData.permanent.flags.allowMaintenance = TRUE; tpmData.permanent.flags.disableFullDALogicInfo = FALSE; tpmData.permanent.flags.readPubek = TRUE; /* release all counters */ for (i = 0; i < TPM_MAX_COUNTERS; i++) memset(&tpmData.permanent.data.counters[i], 0, sizeof(TPM_COUNTER_VALUE)); /* invalidate family and delegates table */ for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { memset(&tpmData.permanent.data.familyTable.famRow[i], 0, sizeof(TPM_FAMILY_TABLE_ENTRY)); } for (i = 0; i < TPM_NUM_DELEGATE_TABLE_ENTRY; i++) { memset(&tpmData.permanent.data.delegateTable.delRow[i], 0, sizeof(TPM_DELEGATE_TABLE_ROW)); } /* release NV storage */ for (i = 0; i < TPM_MAX_NVS; i++) { if (tpmData.permanent.data.nvStorage[i].valid && (tpmData.permanent.data.nvStorage[i].pubInfo.permission.attributes & (TPM_NV_PER_OWNERWRITE | TPM_NV_PER_OWNERREAD))) { tpm_nv_remove_data(&tpmData.permanent.data.nvStorage[i]); } } } TPM_RESULT TPM_OwnerClear(TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_OwnerClear()"); res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; if (tpmData.permanent.flags.disableOwnerClear) return TPM_CLEAR_DISABLED; tpm_owner_clear(); return TPM_SUCCESS; } TPM_RESULT TPM_ForceClear() { info("TPM_ForceClear()"); if (!tpm_get_physical_presence()) return TPM_BAD_PRESENCE; if (tpmData.stclear.flags.disableForceClear) return TPM_CLEAR_DISABLED; tpm_owner_clear(); return TPM_SUCCESS; } TPM_RESULT TPM_DisableOwnerClear(TPM_AUTH *auth1) { TPM_RESULT res; info("TPM_DisableOwnerClear()"); res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); if (res != TPM_SUCCESS) return res; tpmData.permanent.flags.disableOwnerClear = TRUE; return TPM_SUCCESS; } TPM_RESULT TPM_DisableForceClear() { info("TPM_DisableForceClear()"); tpmData.stclear.flags.disableForceClear = TRUE; return TPM_SUCCESS; } TPM_RESULT TSC_PhysicalPresence(TPM_PHYSICAL_PRESENCE physicalPresence) { info("TSC_PhysicalPresence()"); if (!tpmData.permanent.flags.physicalPresenceLifetimeLock) { /* enable physicalPresenceHW or physicalPresenceCMD */ if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) tpmData.permanent.flags.physicalPresenceHWEnable = TRUE; if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE) tpmData.permanent.flags.physicalPresenceCMDEnable = TRUE; } else if (physicalPresence & TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK) { /* set physicalPresenceLifetimeLock */ tpmData.permanent.flags.physicalPresenceLifetimeLock = TRUE; } else if (tpmData.permanent.flags.physicalPresenceCMDEnable && !tpmData.stclear.flags.physicalPresenceLock) { /* set physicalPresence or physicalPresenceLock */ if (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) tpmData.stclear.flags.physicalPresence = TRUE; if (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT) tpmData.stclear.flags.physicalPresence = FALSE; if (physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK) tpmData.stclear.flags.physicalPresenceLock = TRUE; } else { return TPM_BAD_PARAMETER; } return TPM_SUCCESS; } TPM_RESULT TSC_ResetEstablishmentBit() { info("TSC_ResetEstablishmentBit()"); /* locality must be three or four */ if (tpmData.stany.flags.localityModifier != 3 && tpmData.stany.flags.localityModifier != 4) return TPM_BAD_LOCALITY; /* as we do not have such a bit we do nothing and just return true */ return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_startup.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_startup.c 367 2010-02-13 15:52:18Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" /* * Admin Startup and State ([TPM_Part3], Section 3) * This section describes the commands that start a TPM. */ void TPM_Init(TPM_STARTUP_TYPE startupType) { info("TPM_Init()"); /* startup the TPM */ tpmData.stany.flags.postInitialise = TRUE; TPM_SelfTestFull(); TPM_Startup(startupType); } #define SET_TO_ZERO(a) memset(a, 0x00, sizeof(*a)) #define SET_TO_0xFF(a) memset(a, 0xff, sizeof(*a)) #define SET_TO_RAND(a) tpm_get_random_bytes(a, sizeof(*a)) TPM_RESULT TPM_Startup(TPM_STARTUP_TYPE startupType) { int i; info("TPM_Startup(%d)", startupType); if (tpmData.stany.flags.postInitialise == FALSE) return TPM_INVALID_POSTINIT; /* reset STANY_FLAGS */ SET_TO_ZERO(&tpmData.stany.flags); tpmData.stany.flags.tag = TPM_TAG_STANY_FLAGS; /* set data and flags according to the given startup type */ if (startupType == TPM_ST_CLEAR) { /* reset STANY_DATA (invalidates ALL sessions) */ SET_TO_ZERO(&tpmData.stany.data); tpmData.stany.data.tag = TPM_TAG_STANY_DATA; /* init session-context nonce */ SET_TO_RAND(&tpmData.stany.data.contextNonceSession); /* reset PCR values */ for (i = 0; i < TPM_NUM_PCR; i++) { if (tpmData.permanent.data.pcrAttrib[i].pcrReset) SET_TO_0xFF(&tpmData.permanent.data.pcrValue[i].digest); else SET_TO_ZERO(&tpmData.permanent.data.pcrValue[i].digest); } /* reset STCLEAR_FLAGS */ SET_TO_ZERO(&tpmData.stclear.flags); tpmData.stclear.flags.tag = TPM_TAG_STCLEAR_FLAGS; tpmData.stclear.flags.deactivated = tpmData.permanent.flags.deactivated; /* reset STCLEAR_DATA */ SET_TO_ZERO(&tpmData.stclear.data); tpmData.stclear.data.tag = TPM_TAG_STCLEAR_DATA; /* flush volatiles and PCR dependent keys */ for (i = 0; i < TPM_MAX_KEYS; i++) { if (tpmData.permanent.data.keys[i].payload && ((tpmData.permanent.data.keys[i].keyFlags & TPM_KEY_FLAG_VOLATILE) || tpmData.permanent.data.keys[i].parentPCRStatus)) TPM_FlushSpecific(INDEX_TO_KEY_HANDLE(i), TPM_RT_KEY); } /* init key-context nonce */ SET_TO_RAND(&tpmData.stclear.data.contextNonceKey); /* invalidate counter handle */ tpmData.stclear.data.countID = TPM_INVALID_HANDLE; /* reset NV read and write flags */ for (i = 0; i < TPM_MAX_NVS; i++) { tpmData.permanent.data.nvStorage[i].pubInfo.bReadSTClear = FALSE; tpmData.permanent.data.nvStorage[i].pubInfo.bWriteSTClear = FALSE; } } else if (startupType == TPM_ST_STATE) { if (!tpmData.permanent.flags.dataRestored) { error("restoring permanent data failed"); tpmData.permanent.data.testResult = "tpm_restore_permanent_data() failed"; tpmData.permanent.flags.selfTestSucceeded = FALSE; return TPM_FAIL; } } else if (startupType == TPM_ST_DEACTIVATED) { tpmData.stclear.flags.deactivated = TRUE; /* invalidate any saved state */ tpm_erase_permanent_data(); } else { return TPM_BAD_PARAMETER; } tpmData.stany.flags.postInitialise = FALSE; tpmData.stany.flags.TOSPresent = FALSE; return TPM_SUCCESS; } TPM_RESULT TPM_SaveState() { info("TPM_SaveState()"); if (tpmData.permanent.flags.selfTestSucceeded && !tpmData.stclear.flags.deactivated) { return (tpm_store_permanent_data()) ? TPM_FAIL : TPM_SUCCESS; } else { debug("TPM is deactivated or in fail-stop mode, thus the permanent data is not stored"); return TPM_SUCCESS; } } ================================================ FILE: tpm/tpm_storage.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_storage.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "crypto/sha1.h" #include "crypto/rsa.h" #include "tpm_marshalling.h" /* * Storage functions ([TPM_Part3], Section 10) */ TPM_KEY_HANDLE tpm_get_free_key(void) { int i; for (i = 0; i < TPM_MAX_KEYS; i++) { if (!tpmData.permanent.data.keys[i].payload) { tpmData.permanent.data.keys[i].payload = TPM_PT_ASYM; return INDEX_TO_KEY_HANDLE(i); } } return TPM_INVALID_HANDLE; } int tpm_encrypt_public(TPM_PUBKEY_DATA *key, BYTE *in, UINT32 in_size, BYTE *enc, UINT32 *enc_size) { size_t size = *enc_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: debug("unsupported encryption scheme: %d", key->encScheme); return -1; } if (tpm_rsa_encrypt(&key->key, scheme, in, in_size, enc, &size) != 0) { debug("tpm_rsa_encrypt() failed"); return -1; } *enc_size = size; return 0; } int tpm_encrypt_private(TPM_KEY_DATA *key, BYTE *in, UINT32 in_size, BYTE *enc, UINT32 *enc_size) { int res; TPM_PUBKEY_DATA pubKey; pubKey.encScheme = key->encScheme; TPM_RSA_EXTRACT_PUBLIC_KEY(key->key, pubKey.key); res = tpm_encrypt_public(&pubKey, in, in_size, enc, enc_size); free_TPM_PUBKEY_DATA(pubKey); return res; } int tpm_decrypt(TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, BYTE *out, UINT32 *out_size) { size_t size = *out_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: debug("unsupported encryption scheme: %d", key->encScheme); return -1; } if (tpm_rsa_decrypt(&key->key, scheme, enc, enc_size, out, &size) != 0) { debug("tpm_rsa_decrypt() failed"); return -1; } *out_size = size; return 0; } int tpm_encrypt_sealed_data(TPM_KEY_DATA *key, TPM_SEALED_DATA *seal, BYTE *enc, UINT32 *enc_size) { UINT32 len = sizeof_TPM_SEALED_DATA((*seal)); BYTE *buf, *ptr; buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_SEALED_DATA(&ptr, &len, seal) || tpm_encrypt_private(key, buf, sizeof_TPM_SEALED_DATA((*seal)), enc, enc_size)) { tpm_free(buf); return -1; } tpm_free(buf); return 0; } int tpm_decrypt_sealed_data(TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, TPM_SEALED_DATA *seal, BYTE **buf) { BYTE *ptr; *buf = ptr = tpm_malloc(enc_size); if (*buf == NULL || tpm_decrypt(key, enc, enc_size, *buf, &enc_size) || tpm_unmarshal_TPM_SEALED_DATA(&ptr, &enc_size, seal)) { tpm_free(*buf); return -1; } return 0; } int tpm_encrypt_private_key(TPM_KEY_DATA *key, TPM_STORE_ASYMKEY *store, BYTE *enc, UINT32 *enc_size) { UINT32 len = sizeof_TPM_STORE_ASYMKEY((*store)); BYTE *buf, *ptr; buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_STORE_ASYMKEY(&ptr, &len, store) || tpm_encrypt_private(key, buf, sizeof_TPM_STORE_ASYMKEY((*store)), enc, enc_size)) { tpm_free(buf); return -1; } tpm_free(buf); return 0; } int tpm_decrypt_private_key(TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size, TPM_STORE_ASYMKEY *store, BYTE **buf, UINT32 *buf_size) { BYTE *ptr; *buf = ptr = tpm_malloc(enc_size); if (*buf == NULL || tpm_decrypt(key, enc, enc_size, *buf, &enc_size)) { tpm_free(*buf); return -1; } if (buf_size != NULL) *buf_size = enc_size; if (tpm_unmarshal_TPM_STORE_ASYMKEY(&ptr, &enc_size, store) != 0) { tpm_free(*buf); return -1; } if (buf_size != NULL) *buf_size -= enc_size; return 0; } static void tpm_xor_encrypt(TPM_SESSION_DATA *session, TPM_NONCE *nonceOdd, BYTE *data, UINT32 data_size) { BYTE seed[2 * sizeof(TPM_NONCE) + 3 + sizeof(TPM_SECRET)]; BYTE *ptr = seed; /* set up seed */ memcpy(ptr, session->lastNonceEven.nonce, sizeof(TPM_NONCE)); ptr += sizeof(TPM_NONCE); memcpy(ptr, nonceOdd->nonce, sizeof(TPM_NONCE)); ptr += sizeof(TPM_NONCE); memcpy(ptr, (const BYTE*)"XOR", 3); ptr += 3; memcpy(ptr, session->sharedSecret, sizeof(TPM_SECRET)); /* decrypt data */ tpm_rsa_mask_generation(seed, sizeof(seed), data, data_size); } int tpm_compute_key_digest(TPM_KEY *key, TPM_DIGEST *digest) { tpm_sha1_ctx_t sha1; UINT32 len = sizeof_TPM_KEY((*key)); BYTE *buf, *ptr; buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_KEY(&ptr, &len, key)) { tpm_free(buf); return -1; } /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof_TPM_KEY((*key)) - key->encDataSize - 4); tpm_sha1_final(&sha1, digest->digest); tpm_free(buf); return 0; } int tpm_compute_key_data_digest(TPM_KEY_DATA *key, TPM_DIGEST *digest) { tpm_sha1_ctx_t sha1; UINT32 key_len = key->key.size >> 3; BYTE *buf = tpm_malloc(4 + key_len); if (buf == NULL) { debug("tpm_malloc() failed."); return -1; } /* extract modulus */ buf[0] = (key_len >> 24) & 0xff; buf[1] = (key_len >> 16) & 0xff; buf[2] = (key_len >> 8) & 0xff; buf[3] = (key_len >> 0) & 0xff; tpm_rsa_export_modulus(&key->key, &buf[4], NULL); /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, 4 + key_len); tpm_sha1_final(&sha1, digest->digest); tpm_free(buf); return 0; } static int tpm_verify_key_digest(TPM_KEY *key, TPM_DIGEST *digest) { TPM_DIGEST key_digest; if (tpm_compute_key_digest(key, &key_digest)) return -1; return memcmp(key_digest.digest, digest->digest, sizeof(key_digest.digest)); } int tpm_compute_pubkey_checksum(TPM_NONCE *antiReplay, TPM_PUBKEY *pubKey, TPM_DIGEST *checksum) { tpm_sha1_ctx_t sha1; UINT32 len = sizeof_TPM_PUBKEY((*pubKey)); BYTE buf[len], *ptr = buf; if (tpm_marshal_TPM_PUBKEY(&ptr, &len, pubKey)) return -1; /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof_TPM_PUBKEY((*pubKey))); tpm_sha1_update(&sha1, antiReplay->nonce, sizeof(antiReplay->nonce)); tpm_sha1_final(&sha1, checksum->digest); return 0; } int tpm_compute_pubkey_digest(TPM_PUBKEY *key, TPM_DIGEST *digest) { tpm_sha1_ctx_t sha1; UINT32 len = sizeof_TPM_PUBKEY((*key)); BYTE *buf, *ptr; buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_PUBKEY(&ptr, &len, key)) { tpm_free(buf); return -1; } /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof_TPM_PUBKEY((*key))); tpm_sha1_final(&sha1, digest->digest); tpm_free(buf); return 0; } int tpm_setup_key_parms(TPM_KEY_DATA *key, TPM_KEY_PARMS *parms) { size_t exp_len; parms->algorithmID = TPM_ALG_RSA; parms->encScheme = key->encScheme; parms->sigScheme = key->sigScheme; parms->parms.rsa.keyLength = key->key.size; parms->parms.rsa.numPrimes = 2; if (tpm_bn_cmp_ui(key->key.e, 65537) == 0) { parms->parms.rsa.exponentSize = 0; parms->parms.rsa.exponent = NULL; } else { parms->parms.rsa.exponentSize = tpm_rsa_exponent_length(&key->key); parms->parms.rsa.exponent = tpm_malloc(parms->parms.rsa.exponentSize); if (parms->parms.rsa.exponent == NULL) return -1; tpm_rsa_export_exponent(&key->key, parms->parms.rsa.exponent, &exp_len); parms->parms.rsa.exponentSize = exp_len; } parms->parmSize = 12 + parms->parms.rsa.exponentSize; return 0; } int tpm_setup_pubkey_data(TPM_PUBKEY *in, TPM_PUBKEY_DATA *out) { out->valid = TRUE; out->encScheme = in->algorithmParms.encScheme; out->sigScheme = in->algorithmParms.sigScheme; out->key.size = in->algorithmParms.parms.rsa.keyLength; if (tpm_rsa_import_public_key(&out->key, RSA_MSB_FIRST, in->pubKey.key, in->pubKey.keyLength, in->algorithmParms.parms.rsa.exponent, in->algorithmParms.parms.rsa.exponentSize) != 0) return -1; return 0; } int tpm_extract_pubkey(TPM_KEY_DATA *key, TPM_PUBKEY *pubKey) { pubKey->pubKey.keyLength = key->key.size >> 3; pubKey->pubKey.key = tpm_malloc(pubKey->pubKey.keyLength); if (pubKey->pubKey.key == NULL) { debug("tpm_malloc() failed."); return -1; } tpm_rsa_export_modulus(&key->key, pubKey->pubKey.key, NULL); if (tpm_setup_key_parms(key, &pubKey->algorithmParms) != 0) { debug("tpm_setup_key_parms() failed."); tpm_free(pubKey->pubKey.key); return -1; } return 0; } int tpm_extract_store_pubkey(TPM_KEY_DATA *key, TPM_STORE_PUBKEY *pubKey) { pubKey->keyLength = key->key.size >> 3; pubKey->key = tpm_malloc(pubKey->keyLength); if (pubKey->key == NULL) { debug("tpm_malloc() failed."); return -1; } tpm_rsa_export_modulus(&key->key, pubKey->key, NULL); return 0; } static int compute_store_digest(TPM_STORED_DATA *store, TPM_DIGEST *digest) { tpm_sha1_ctx_t sha1; UINT32 len = sizeof_TPM_STORED_DATA((*store)); BYTE *buf, *ptr; buf = ptr = tpm_malloc(len); if (buf == NULL || tpm_marshal_TPM_STORED_DATA(&ptr, &len, store)) { tpm_free(buf); return -1; } /* compute SHA1 hash */ tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof_TPM_STORED_DATA((*store))); tpm_sha1_final(&sha1, digest->digest); tpm_free(buf); return 0; } static int verify_store_digest(TPM_STORED_DATA *store, TPM_DIGEST *digest) { TPM_DIGEST store_digest; if (compute_store_digest(store, &store_digest)) return -1; return memcmp(store_digest.digest, digest->digest, sizeof(store_digest.digest)); } TPM_RESULT TPM_Seal(TPM_KEY_HANDLE keyHandle, TPM_ENCAUTH *encAuth, UINT32 pcrInfoSize, TPM_PCR_INFO *pcrInfo, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, TPM_STORED_DATA *sealedData) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_SESSION_DATA *session; TPM_SEALED_DATA seal; info("TPM_Seal()"); if (inDataSize == 0) return TPM_BAD_PARAMETER; /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; auth1->continueAuthSession = FALSE; session = tpm_get_auth(auth1->authHandle); if (session->type != TPM_ST_OSAP) return TPM_AUTHFAIL; /* verify key properties */ if (key->keyUsage != TPM_KEY_STORAGE || key->keyFlags & TPM_KEY_FLAG_MIGRATABLE) return TPM_INVALID_KEYUSAGE; /* setup store */ if (pcrInfo->tag == TPM_TAG_PCR_INFO_LONG) { sealedData->tag = TPM_TAG_STORED_DATA12; sealedData->et = 0x0000; } else { sealedData->tag = 0x0101; sealedData->et = 0x0000; } sealedData->encDataSize = 0; sealedData->encData = NULL; sealedData->sealInfoSize = pcrInfoSize; if (pcrInfoSize > 0) { sealedData->sealInfoSize = pcrInfoSize; memcpy(&sealedData->sealInfo, pcrInfo, sizeof(TPM_PCR_INFO)); res = tpm_compute_pcr_digest(&pcrInfo->creationPCRSelection, &sealedData->sealInfo.digestAtCreation, NULL); if (res != TPM_SUCCESS) return res; sealedData->sealInfo.localityAtCreation = tpmData.stany.flags.localityModifier; } /* setup seal */ seal.payload = TPM_PT_SEAL; memcpy(&seal.tpmProof, &tpmData.permanent.data.tpmProof, sizeof(TPM_NONCE)); if (compute_store_digest(sealedData, &seal.storedDigest)) { debug("TPM_Seal(): compute_store_digest() failed."); return TPM_FAIL; } if ((session->entityType & 0xff00) != TPM_ET_XOR) return TPM_INAPPROPRIATE_ENC; tpm_decrypt_auth_secret(*encAuth, session->sharedSecret, &session->lastNonceEven, seal.authData); seal.dataSize = inDataSize; seal.data = inData; /* encrypt sealed data */ sealedData->encDataSize = key->key.size >> 3; sealedData->encData = tpm_malloc(sealedData->encDataSize); if (sealedData->encData == NULL) return TPM_NOSPACE; if (tpm_encrypt_sealed_data(key, &seal, sealedData->encData, &sealedData->encDataSize)) { tpm_free(sealedData->encData); return TPM_ENCRYPT_ERROR; } return TPM_SUCCESS; } TPM_RESULT TPM_Sealx(TPM_KEY_HANDLE keyHandle, TPM_ENCAUTH *encAuth, UINT32 pcrInfoSize, TPM_PCR_INFO *pcrInfo, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, TPM_STORED_DATA *sealedData) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_SESSION_DATA *session; TPM_SEALED_DATA seal; info("TPM_Sealx()"); if (inDataSize == 0) return TPM_BAD_PARAMETER; /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; auth1->continueAuthSession = FALSE; session = tpm_get_auth(auth1->authHandle); if (session->type != TPM_ST_OSAP) return TPM_AUTHFAIL; /* verify key properties */ if (key->keyUsage != TPM_KEY_STORAGE || key->keyFlags & TPM_KEY_FLAG_MIGRATABLE) return TPM_INVALID_KEYUSAGE; /* setup store */ if (pcrInfo->tag != TPM_TAG_PCR_INFO_LONG) return TPM_BAD_PARAMETER; if ((session->entityType & 0xff00) != TPM_ET_XOR) return TPM_INAPPROPRIATE_ENC; sealedData->tag = TPM_TAG_STORED_DATA12; sealedData->et = TPM_ET_XOR | TPM_ET_KEY; sealedData->encDataSize = 0; sealedData->encData = NULL; sealedData->sealInfoSize = pcrInfoSize; if (pcrInfoSize > 0) { sealedData->sealInfoSize = pcrInfoSize; memcpy(&sealedData->sealInfo, pcrInfo, sizeof(TPM_PCR_INFO)); res = tpm_compute_pcr_digest(&pcrInfo->creationPCRSelection, &sealedData->sealInfo.digestAtCreation, NULL); if (res != TPM_SUCCESS) return res; sealedData->sealInfo.localityAtCreation = tpmData.stany.flags.localityModifier; } /* setup seal */ seal.payload = TPM_PT_SEAL; memcpy(&seal.tpmProof, &tpmData.permanent.data.tpmProof, sizeof(TPM_NONCE)); if (compute_store_digest(sealedData, &seal.storedDigest)) { debug("TPM_Sealx(): compute_store_digest() failed."); return TPM_FAIL; } tpm_decrypt_auth_secret(*encAuth, session->sharedSecret, &session->lastNonceEven, seal.authData); tpm_xor_encrypt(session, &auth1->nonceOdd, inData, inDataSize); seal.dataSize = inDataSize; seal.data = inData; /* encrypt sealed data */ sealedData->encDataSize = key->key.size >> 3; sealedData->encData = tpm_malloc(sealedData->encDataSize); if (sealedData->encData == NULL) return TPM_NOSPACE; if (tpm_encrypt_sealed_data(key, &seal, sealedData->encData, &sealedData->encDataSize)) { tpm_free(sealedData->encData); return TPM_ENCRYPT_ERROR; } return TPM_SUCCESS; } TPM_RESULT TPM_Unseal(TPM_KEY_HANDLE parentHandle, TPM_STORED_DATA *inData, TPM_AUTH *auth1, TPM_AUTH *auth2, UINT32 *sealedDataSize, BYTE **secret) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_SESSION_DATA *session; TPM_SEALED_DATA seal; BYTE *seal_buf; TPM_DIGEST digest; info("TPM_Unseal()"); /* get key */ key = tpm_get_key(parentHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization, if only auth1 is present we use it for the data */ if (auth2->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; auth1->continueAuthSession = FALSE; session = tpm_get_auth(auth1->authHandle); } else { session = NULL; } /* verify key properties */ if (key->keyUsage != TPM_KEY_STORAGE || key->keyFlags & TPM_KEY_FLAG_MIGRATABLE) return TPM_INVALID_KEYUSAGE; /* verify PCR info */ if (inData->sealInfoSize > 0) { res = tpm_compute_pcr_digest(&inData->sealInfo.releasePCRSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &inData->sealInfo.digestAtRelease, sizeof(TPM_DIGEST))) return TPM_WRONGPCRVAL; if (inData->sealInfo.tag == TPM_TAG_PCR_INFO_LONG && !(inData->sealInfo.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; } /* decrypt sealed data */ if (tpm_decrypt_sealed_data(key, inData->encData, inData->encDataSize, &seal, &seal_buf)) return TPM_DECRYPT_ERROR; inData->encDataSize = 0; if (seal.payload != TPM_PT_SEAL || memcmp(&tpmData.permanent.data.tpmProof, &seal.tpmProof, sizeof(TPM_NONCE)) || verify_store_digest(inData, &seal.storedDigest)) { tpm_free(seal_buf); return TPM_NOTSEALED_BLOB; } /* verify data auth */ if (auth2->authHandle != TPM_INVALID_HANDLE) { res = tpm_verify_auth(auth2, seal.authData, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res; } else { res = tpm_verify_auth(auth1, seal.authData, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) return res; } /* encrypt data if required */ debug("entity type = %04x", inData->et & 0xff00); if (inData->et != 0) { if (auth2->authHandle == TPM_INVALID_HANDLE) return TPM_AUTHFAIL; if (session->type != TPM_ST_OSAP) return TPM_BAD_MODE; if ((inData->et & 0xff00) == TPM_ET_XOR) { tpm_xor_encrypt(session, &auth1->nonceOdd, seal.data, seal.dataSize); } else return TPM_INAPPROPRIATE_ENC; } /* return secret */ *sealedDataSize = seal.dataSize; *secret = tpm_malloc(*sealedDataSize); if (*secret == NULL) { tpm_free(seal_buf); return TPM_NOSPACE; } memcpy(*secret, seal.data, seal.dataSize); tpm_free(seal_buf); return TPM_SUCCESS; } TPM_RESULT TPM_UnBind(TPM_KEY_HANDLE keyHandle, UINT32 inDataSize, BYTE *inData, TPM_AUTH *auth1, UINT32 *outDataSize, BYTE **outData) { TPM_RESULT res; TPM_KEY_DATA *key; size_t out_len; int scheme; info("TPM_UnBind()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify auth */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } /* verify key properties */ if (key->keyUsage != TPM_KEY_BIND && key->keyUsage != TPM_KEY_LEGACY) return TPM_INVALID_KEYUSAGE; /* the size of the input data muss be greater than zero */ if (inDataSize == 0) return TPM_BAD_PARAMETER; /* decrypt data */ *outDataSize = inDataSize; *outData = tpm_malloc(*outDataSize); if (*outData == NULL) return TPM_NOSPACE; 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: tpm_free(*outData); return TPM_DECRYPT_ERROR; } if (tpm_rsa_decrypt(&key->key, scheme, inData, inDataSize, *outData, &out_len)) { tpm_free(*outData); return TPM_DECRYPT_ERROR; } *outDataSize = out_len; /* verify data if it is of type TPM_BOUND_DATA */ if (key->encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1 || key->keyUsage != TPM_KEY_LEGACY) { if (*outDataSize < 5 || memcmp(*outData, "\x01\x01\00\x00\x02", 5) != 0) { tpm_free(*outData); return TPM_DECRYPT_ERROR; } *outDataSize -= 5; memmove(*outData, &(*outData)[5], *outDataSize); } return TPM_SUCCESS; } TPM_RESULT TPM_CreateWrapKey(TPM_KEY_HANDLE parentHandle, TPM_ENCAUTH *dataUsageAuth, TPM_ENCAUTH *dataMigrationAuth, TPM_KEY *keyInfo, TPM_AUTH *auth1, TPM_KEY *wrappedKey) { TPM_RESULT res; TPM_KEY_DATA *parent; TPM_SESSION_DATA *session; TPM_STORE_ASYMKEY store; tpm_rsa_private_key_t rsa; UINT32 key_length; info("TPM_CreateWrapKey()"); /* get parent key */ parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify 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 && session->type != TPM_ST_DSAP) return TPM_AUTHFAIL; /* verify key parameters */ if (parent->keyUsage != TPM_KEY_STORAGE || parent->encScheme == TPM_ES_NONE || ((parent->keyFlags & TPM_KEY_FLAG_MIGRATABLE) && !(keyInfo->keyFlags & TPM_KEY_FLAG_MIGRATABLE)) || keyInfo->keyUsage == TPM_KEY_IDENTITY || keyInfo->keyUsage == TPM_KEY_AUTHCHANGE) return TPM_INVALID_KEYUSAGE; if (keyInfo->algorithmParms.algorithmID != TPM_ALG_RSA || keyInfo->algorithmParms.parmSize == 0 || keyInfo->algorithmParms.parms.rsa.keyLength < 512 || keyInfo->algorithmParms.parms.rsa.numPrimes != 2 || keyInfo->algorithmParms.parms.rsa.exponentSize != 0) return TPM_BAD_KEY_PROPERTY; if (tpmData.permanent.flags.FIPS && (keyInfo->algorithmParms.parms.rsa.keyLength < 1024 || keyInfo->authDataUsage == TPM_AUTH_NEVER || keyInfo->keyUsage == TPM_KEY_LEGACY)) return TPM_NOTFIPS; if ((keyInfo->keyUsage == TPM_KEY_STORAGE || keyInfo->keyUsage == TPM_KEY_MIGRATE) && (keyInfo->algorithmParms.algorithmID != TPM_ALG_RSA || keyInfo->algorithmParms.parms.rsa.keyLength != 2048 || keyInfo->algorithmParms.sigScheme != TPM_SS_NONE || keyInfo->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1)) return TPM_BAD_KEY_PROPERTY; /* setup the wrapped key */ memcpy(wrappedKey, keyInfo, sizeof(TPM_KEY)); /* setup key store */ store.payload = TPM_PT_ASYM; tpm_decrypt_auth_secret(*dataUsageAuth, session->sharedSecret, &session->lastNonceEven, store.usageAuth); if (keyInfo->keyFlags & TPM_KEY_FLAG_MIGRATABLE) { tpm_decrypt_auth_secret(*dataMigrationAuth, session->sharedSecret, &auth1->nonceOdd, store.migrationAuth); /* clear PCR digest */ if (keyInfo->PCRInfoSize > 0) { memset(keyInfo->PCRInfo.digestAtCreation.digest, 0, sizeof(keyInfo->PCRInfo.digestAtCreation.digest)); keyInfo->PCRInfo.localityAtCreation = 0; } } else { memcpy(store.migrationAuth, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_SECRET)); /* compute PCR digest */ if (keyInfo->PCRInfoSize > 0) { tpm_compute_pcr_digest(&keyInfo->PCRInfo.creationPCRSelection, &keyInfo->PCRInfo.digestAtCreation, NULL); keyInfo->PCRInfo.localityAtCreation = tpmData.stany.flags.localityModifier; } } /* generate key and store it */ key_length = keyInfo->algorithmParms.parms.rsa.keyLength; if (tpm_rsa_generate_key(&rsa, key_length)) { debug("TPM_CreateWrapKey(): tpm_rsa_generate_key() failed."); return TPM_FAIL; } wrappedKey->pubKey.keyLength = key_length >> 3; wrappedKey->pubKey.key = tpm_malloc(wrappedKey->pubKey.keyLength); store.privKey.keyLength = key_length >> 4; store.privKey.key = tpm_malloc(store.privKey.keyLength); wrappedKey->encDataSize = parent->key.size >> 3; wrappedKey->encData = tpm_malloc(wrappedKey->encDataSize); if (wrappedKey->pubKey.key == NULL || store.privKey.key == NULL || wrappedKey->encData == NULL) { tpm_rsa_release_private_key(&rsa); tpm_free(wrappedKey->pubKey.key); tpm_free(store.privKey.key); tpm_free(wrappedKey->encData); return TPM_NOSPACE; } tpm_rsa_export_modulus(&rsa, wrappedKey->pubKey.key, NULL); tpm_rsa_export_prime1(&rsa, store.privKey.key, NULL); tpm_rsa_release_private_key(&rsa); /* compute the digest of the wrapped key (without encData) */ if (tpm_compute_key_digest(wrappedKey, &store.pubDataDigest)) { debug("TPM_CreateWrapKey(): tpm_compute_key_digest() failed."); return TPM_FAIL; } /* encrypt private key data */ if (tpm_encrypt_private_key(parent, &store, wrappedKey->encData, &wrappedKey->encDataSize)) { tpm_free(wrappedKey->pubKey.key); tpm_free(store.privKey.key); tpm_free(wrappedKey->encData); return TPM_ENCRYPT_ERROR; } tpm_free(store.privKey.key); return TPM_SUCCESS; } TPM_RESULT TPM_LoadKey(TPM_KEY_HANDLE parentHandle, TPM_KEY *inKey, TPM_AUTH *auth1, TPM_KEY_HANDLE *inkeyHandle) { TPM_RESULT res; TPM_KEY_DATA *parent, *key; BYTE *key_buf; TPM_STORE_ASYMKEY store; info("TPM_LoadKey()"); /* get parent key */ debug("parentHandle = %08x", parentHandle); parent = tpm_get_key(parentHandle); if (parent == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE) { debug("authDataUsage = %02x", parent->authDataUsage); res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle); if (res != TPM_SUCCESS) return res; } else if (parent->authDataUsage != TPM_AUTH_NEVER) { debug("TPM_LoadKey(): parent key requires authorization."); return TPM_AUTHFAIL; } if (parent->keyUsage != TPM_KEY_STORAGE) return TPM_INVALID_KEYUSAGE; /* verify key properties */ if (inKey->algorithmParms.algorithmID != TPM_ALG_RSA || inKey->algorithmParms.parmSize == 0 || inKey->algorithmParms.parms.rsa.keyLength > 2048 || inKey->algorithmParms.parms.rsa.numPrimes != 2) return TPM_BAD_KEY_PROPERTY; if (inKey->keyUsage == TPM_KEY_AUTHCHANGE) return TPM_INVALID_KEYUSAGE; if (inKey->keyUsage == TPM_KEY_STORAGE && (inKey->algorithmParms.algorithmID != TPM_ALG_RSA || inKey->algorithmParms.parms.rsa.keyLength != 2048 || inKey->algorithmParms.sigScheme != TPM_SS_NONE)) return TPM_INVALID_KEYUSAGE; if (inKey->keyUsage == TPM_KEY_IDENTITY && (inKey->keyFlags & TPM_KEY_FLAG_MIGRATABLE || inKey->algorithmParms.algorithmID != TPM_ALG_RSA || inKey->algorithmParms.parms.rsa.keyLength != 2048 || inKey->algorithmParms.encScheme != TPM_ES_NONE)) return TPM_INVALID_KEYUSAGE; /* decrypt private key */ if (tpm_decrypt_private_key(parent, inKey->encData, inKey->encDataSize, &store, &key_buf, NULL)) return TPM_DECRYPT_ERROR; /* get a free key-slot, if any free slot is left */ *inkeyHandle = tpm_get_free_key(); key = tpm_get_key(*inkeyHandle); if (key == NULL) { tpm_free(key_buf); return TPM_NOSPACE; } /* import key */ if (tpm_verify_key_digest(inKey, &store.pubDataDigest) != 0) { debug("tpm_verify_key_digest() failed."); memset(key, 0, sizeof(TPM_KEY_DATA)); tpm_free(key_buf); return TPM_FAIL; } if (inKey->pubKey.keyLength != (store.privKey.keyLength * 2)) { debug("size of the public modulus does not match the secret prime"); memset(key, 0, sizeof(TPM_KEY_DATA)); tpm_free(key_buf); return TPM_FAIL; } if (tpm_rsa_import_key(&key->key, RSA_MSB_FIRST, inKey->pubKey.key, inKey->pubKey.keyLength, inKey->algorithmParms.parms.rsa.exponent, inKey->algorithmParms.parms.rsa.exponentSize, store.privKey.key, NULL)) { debug("tpm_rsa_import_key() failed."); memset(key, 0, sizeof(TPM_KEY_DATA)); tpm_free(key_buf); return TPM_FAIL; } /* verify tpmProof */ if (!(inKey->keyFlags & TPM_KEY_FLAG_MIGRATABLE)) { if (memcmp(tpmData.permanent.data.tpmProof.nonce, store.migrationAuth, sizeof(TPM_NONCE))) { debug("TPM_LoadKey(): tpmProof verification failed."); memset(key, 0, sizeof(TPM_KEY_DATA)); tpm_free(key_buf); return TPM_FAIL; } } if (store.payload) key->payload = store.payload; key->keyUsage = inKey->keyUsage; key->keyFlags = inKey->keyFlags; key->authDataUsage = inKey->authDataUsage; key->encScheme = inKey->algorithmParms.encScheme; key->sigScheme = inKey->algorithmParms.sigScheme; memcpy(key->usageAuth, store.usageAuth, sizeof(TPM_SECRET)); memcpy(key->migrationAuth, store.migrationAuth, sizeof(TPM_SECRET)); /* setup PCR info */ if (inKey->PCRInfoSize > 0) { memcpy(&key->pcrInfo, &inKey->PCRInfo, sizeof(TPM_PCR_INFO)); key->keyFlags |= TPM_KEY_FLAG_HAS_PCR; } else { key->keyFlags |= TPM_KEY_FLAG_PCR_IGNORE; key->keyFlags &= ~TPM_KEY_FLAG_HAS_PCR; } key->parentPCRStatus = parent->parentPCRStatus; tpm_free(key_buf); return TPM_SUCCESS; } TPM_RESULT TPM_LoadKey2(TPM_KEY_HANDLE parentHandle, TPM_KEY *inKey, TPM_AUTH *auth1, TPM_KEY_HANDLE *inkeyHandle) { info("TPM_LoadKey2()"); return TPM_LoadKey(parentHandle, inKey, auth1, inkeyHandle); } TPM_RESULT internal_TPM_LoadKey(TPM_KEY *inKey, TPM_KEY_HANDLE *inkeyHandle) { TPM_KEY_DATA *parent, *key; BYTE *key_buf; TPM_STORE_ASYMKEY store; info("internal_TPM_LoadKey()"); /* get SRK */ parent = tpm_get_key(TPM_KH_SRK); if (parent == NULL) return TPM_FAIL; /* verify key properties */ if (inKey->algorithmParms.algorithmID != TPM_ALG_RSA || inKey->algorithmParms.parmSize == 0 || inKey->algorithmParms.parms.rsa.keyLength > 2048 || inKey->algorithmParms.parms.rsa.numPrimes != 2) return TPM_BAD_KEY_PROPERTY; /* decrypt private key */ if (tpm_decrypt_private_key(parent, inKey->encData, inKey->encDataSize, &store, &key_buf, NULL)) return TPM_DECRYPT_ERROR; /* get a free key-slot, if any free slot is left */ *inkeyHandle = tpm_get_free_key(); key = tpm_get_key(*inkeyHandle); if (key == NULL) { tpm_free(key_buf); return TPM_NOSPACE; } /* import key */ if (tpm_verify_key_digest(inKey, &store.pubDataDigest) || inKey->pubKey.keyLength != (store.privKey.keyLength * 2) || tpm_rsa_import_key(&key->key, RSA_MSB_FIRST, inKey->pubKey.key, inKey->pubKey.keyLength, inKey->algorithmParms.parms.rsa.exponent, inKey->algorithmParms.parms.rsa.exponentSize, store.privKey.key, NULL)) { debug("internal_LoadKey(): tpm_verify_key_digest() or tpm_rsa_import_key() failed."); memset(key, 0, sizeof(TPM_KEY_DATA)); tpm_free(key_buf); return TPM_FAIL; } key->keyUsage = inKey->keyUsage; key->keyFlags = inKey->keyFlags; key->authDataUsage = inKey->authDataUsage; key->encScheme = inKey->algorithmParms.encScheme; key->sigScheme = inKey->algorithmParms.sigScheme; memcpy(key->usageAuth, store.usageAuth, sizeof(TPM_SECRET)); /* setup PCR info */ if (inKey->PCRInfoSize > 0) { memcpy(&key->pcrInfo, &inKey->PCRInfo, sizeof(TPM_PCR_INFO)); key->keyFlags |= TPM_KEY_FLAG_HAS_PCR; } else { key->keyFlags |= TPM_KEY_FLAG_PCR_IGNORE; key->keyFlags &= ~TPM_KEY_FLAG_HAS_PCR; } key->parentPCRStatus = parent->parentPCRStatus; tpm_free(key_buf); return TPM_SUCCESS; } TPM_RESULT TPM_GetPubKey(TPM_KEY_HANDLE keyHandle, TPM_AUTH *auth1, TPM_PUBKEY *pubKey) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_DIGEST digest; info("TPM_GetPubKey()"); /* get key */ if (keyHandle == TPM_KH_SRK && !tpmData.permanent.flags.readSRKPub) return TPM_INVALID_KEYHANDLE; key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || (key->authDataUsage != TPM_AUTH_NEVER && key->authDataUsage != TPM_AUTH_PRIV_USE_ONLY)) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } if (!(key->keyFlags & TPM_KEY_FLAG_PCR_IGNORE)) { res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection, &digest, NULL); if (res != TPM_SUCCESS) return res; if (memcmp(&digest, &key->pcrInfo.digestAtRelease, sizeof(TPM_DIGEST))) return TPM_WRONGPCRVAL; if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG && !(key->pcrInfo.localityAtRelease & (1 << tpmData.stany.flags.localityModifier))) return TPM_BAD_LOCALITY; } /* extract pubKey */ if (tpm_extract_pubkey(key, pubKey) != 0) return TPM_FAIL; return TPM_SUCCESS; } ================================================ FILE: tpm/tpm_structures.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * 2005-2008 Heiko Stamer * * 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_structures.h 467 2011-07-19 17:36:12Z mast $ */ #ifndef _TPM_STRUCTURES_H_ #define _TPM_STRUCTURES_H_ #include "tpm_emulator.h" #include "crypto/rsa.h" /* * The following types and structures are specified in * TPM Main Part 2 TPM Structures [TPM_Part2]. */ /* * Basic Data Types ([TPM_Part2], Section 2.2.1 and 2.2.2) */ typedef uint8_t BYTE; typedef uint16_t UINT16; typedef uint32_t UINT32; typedef uint64_t UINT64; typedef BYTE BOOL; #define TRUE 0x01 #define FALSE 0x00 /* * TPM Helper Data Types ([TPM_Part2], Section 2.2.3) */ typedef BYTE TPM_AUTH_DATA_USAGE; typedef BYTE TPM_PAYLOAD_TYPE; typedef BYTE TPM_VERSION_BYTE; typedef BYTE TPM_DA_STATE; typedef UINT16 TPM_TAG; typedef UINT16 TPM_PROTOCOL_ID; typedef UINT16 TPM_STARTUP_TYPE; typedef UINT16 TPM_ENC_SCHEME; typedef UINT16 TPM_SIG_SCHEME; typedef UINT16 TPM_MIGRATE_SCHEME; typedef UINT16 TPM_PHYSICAL_PRESENCE; typedef UINT16 TPM_ENTITY_TYPE; typedef UINT16 TPM_KEY_USAGE; typedef UINT16 TPM_EK_TYPE; typedef UINT16 TPM_STRUCTURE_TAG; typedef UINT16 TPM_PLATFORM_SPECIFIC; typedef UINT32 TPM_COMMAND_CODE; typedef UINT32 TPM_CAPABILITY_AREA; typedef UINT32 TPM_KEY_FLAGS; typedef UINT32 TPM_ALGORITHM_ID; typedef UINT32 TPM_MODIFIER_INDICATOR; typedef UINT32 TPM_ACTUAL_COUNT; typedef UINT32 TPM_TRANSPORT_ATTRIBUTES; typedef UINT32 TPM_AUTHHANDLE; typedef UINT32 TPM_DIRINDEX; typedef UINT32 TPM_KEY_HANDLE; typedef UINT32 TPM_PCRINDEX; typedef UINT32 TPM_RESULT; typedef UINT32 TPM_RESOURCE_TYPE; typedef UINT32 TPM_KEY_CONTROL; typedef UINT32 TPM_NV_INDEX; typedef UINT32 TPM_FAMILY_ID; typedef UINT32 TPM_FAMILY_VERIFICATION; typedef UINT32 TPM_STARTUP_EFFECTS; typedef UINT32 TPM_SYM_MODE; typedef UINT32 TPM_FAMILY_FLAGS; typedef UINT32 TPM_DELEGATE_INDEX; typedef UINT32 TPM_CMK_DELEGATE; typedef UINT32 TPM_COUNT_ID; typedef UINT32 TPM_REDIT_COMMAND; typedef UINT32 TPM_TRANSHANDLE; typedef UINT32 TPM_HANDLE; typedef UINT32 TPM_FAMILY_OPERATION; /* * Vendor Specific ([TPM_Part2], Section 2.2.4) */ #define TPM_Vendor_Specific32 0x00000400 #define TPM_Vendor_Specific8 0x80 /* * Structure Tags ([TPM_Part2], Section 3.1) * are defined together with the dedicated structures. */ /* * TPM_RESOURCE_TYPE ([TPM_Part2], Section 4.1) * Specifies the resource type. */ #define TPM_RT_KEY 0x00000001 #define TPM_RT_AUTH 0x00000002 #define TPM_RT_HASH 0x00000003 #define TPM_RT_TRANS 0x00000004 #define TPM_RT_CONTEXT 0x00000005 #define TPM_RT_COUNTER 0x00000006 #define TPM_RT_DELEGATE 0x00000007 #define TPM_RT_DAA_TPM 0x00000008 #define TPM_RT_DAA_V0 0x00000009 #define TPM_RT_DAA_V1 0x0000000A /* * TPM_PAYLOAD_TYPE ([TPM_Part2], Section 4.2) * This specifies the type of payload in various messages. */ #define TPM_PT_ASYM 0x01 #define TPM_PT_BIND 0x02 #define TPM_PT_MIGRATE 0x03 #define TPM_PT_MAINT 0x04 #define TPM_PT_SEAL 0x05 #define TPM_PT_MIGRATE_RESTRICTED 0x06 #define TPM_PT_MIGRATE_EXTERNAL 0x07 #define TPM_PT_CMK_MIGRATE 0x08 /* 0x09 - 0x7F Reserved for future use by TPM */ /* 0x80 - 0xFF Vendor specific payloads */ #define TPM_PT_NONE 0x00 /* * TPM_ENTITY_TYPE ([TPM_Part2], Section 4.3) * This specifies the types of entity and ADIP encryption schemes * that are supported by the TPM. * * The LSB is used to indicate the entity type. The MSB is used to * indicate the ADIP encryption scheme when applicable. * * For compatibility with TPM 1.1, some values are maintained. */ /* LSB Values */ #define TPM_ET_KEYHANDLE 0x01 #define TPM_ET_OWNER 0x02 #define TPM_ET_DATA 0x03 #define TPM_ET_SRK 0x04 #define TPM_ET_KEY 0x05 #define TPM_ET_REVOKE 0x06 #define TPM_ET_DEL_OWNER_BLOB 0x07 #define TPM_ET_DEL_ROW 0x08 #define TPM_ET_DEL_KEY_BLOB 0x09 #define TPM_ET_COUNTER 0x0A #define TPM_ET_NV 0x0B #define TPM_ET_OPERATOR 0x0C #define TPM_ET_VERIFICATION_AUTH 0x0D #define TPM_ET_RESERVED_HANDLE 0x40 /* MSB Values */ #define TPM_ET_XOR 0x00 #define TPM_ET_AES128_CTR 0x06 /* * Reserved Key Handles ([TPM_Part2], Section 4.4.1) * These values specify specific keys or specific actions for the TPM. */ #define TPM_KH_SRK 0x40000000 #define TPM_KH_OWNER 0x40000001 #define TPM_KH_REVOKE 0x40000002 #define TPM_KH_TRANSPORT 0x40000003 #define TPM_KH_OPERATOR 0x40000004 #define TPM_KH_ADMIN 0x40000005 #define TPM_KH_EK 0x40000006 /* * TPM_STARTUP_TYPE ([TPM_Part2], Section 4.5) * To specify what type of startup is occurring. */ #define TPM_ST_CLEAR 0x0001 #define TPM_ST_STATE 0x0002 #define TPM_ST_DEACTIVATED 0x0003 /* * TPM_STARTUP_EFFECTS ([TPM_Part2], Section 4.6) * This structure lists for the various resources and sessions on a TPM * the affect that TPM_Startup has on the values. */ /* 31-8 reserved and must be 0 */ #define TPM_STARTUP_RT_DAA_TPM_ST_STATE (1 << 8) #define TPM_STARTUP_AUDIT_DIGEST_IGNORE (1 << 7) #define TPM_STARTUP_AUDIT_DIGEST_ST_CLEAR (1 << 6) #define TPM_STARTUP_AUDIT_DIGEST_ST_ANY (1 << 5) #define TPM_STARTUP_RT_KEY_ST_ANY (1 << 4) #define TPM_STARTUP_RT_AUTH_ST_STATE (1 << 3) #define TPM_STARTUP_RT_HASH_ST_STATE (1 << 2) #define TPM_STARTUP_RT_TRANS_ST_STATE (1 << 1) #define TPM_STARTUP_RT_CONTEXT_ST_STATE (1 << 0) /* * TPM_PROTOCOL_ID ([TPM_Part2], Section 4.7) * This value identifies the protocol in use. */ #define TPM_PID_OIAP 0x0001 #define TPM_PID_OSAP 0x0002 #define TPM_PID_ADIP 0x0003 #define TPM_PID_ADCP 0x0004 #define TPM_PID_OWNER 0x0005 #define TPM_PID_DSAP 0x0006 #define TPM_PID_TRANSPORT 0x0007 /* * TPM_ALGORITHM_ID ([TPM_Part2], Section 4.8) * This table defines the types of algorithms which may be supported by the TPM. */ #define TPM_ALG_RSA 0x00000001 #define TPM_ALG_DES 0x00000002 #define TPM_ALG_3DES 0x00000003 #define TPM_ALG_SHA 0x00000004 #define TPM_ALG_HMAC 0x00000005 #define TPM_ALG_AES128 0x00000006 #define TPM_ALG_MGF1 0x00000007 #define TPM_ALG_AES192 0x00000008 #define TPM_ALG_AES256 0x00000009 #define TPM_ALG_XOR 0x0000000A /* * TPM_PHYSICAL_PRESENCE ([TPM_Part2], Section 4.9) * Values to setup the Physical Presence */ #define TPM_PHYSICAL_PRESENCE_HW_DISABLE 0x0200 #define TPM_PHYSICAL_PRESENCE_CMD_DISABLE 0x0100 #define TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK 0x0080 #define TPM_PHYSICAL_PRESENCE_HW_ENABLE 0x0040 #define TPM_PHYSICAL_PRESENCE_CMD_ENABLE 0x0020 #define TPM_PHYSICAL_PRESENCE_NOTPRESENT 0x0010 #define TPM_PHYSICAL_PRESENCE_PRESENT 0x0008 #define TPM_PHYSICAL_PRESENCE_LOCK 0x0004 /* * TPM_MIGRATE_SCHEME ([TPM_Part2], Section 4.10) * Indicates how the StartMigrate command should handle the * migration of the encrypted blob. */ #define TPM_MS_MIGRATE 0x0001 #define TPM_MS_REWRAP 0x0002 #define TPM_MS_MAINT 0x0003 #define TPM_MS_RESTRICT_MIGRATE 0x0004 #define TPM_MS_RESTRICT_APPROVE 0x0005 /* * TPM_EK_TYPE ([TPM_Part2], Section 4.11) * Indicates what type of information that the EK is dealing with. */ #define TPM_EK_TYPE_ACTIVATE 0x0001 #define TPM_EK_TYPE_AUTH 0x0002 /* * TPM_PLATFORM_SPECIFIC ([TPM_Part2], Section 4.12) * Indicates the platform specific spec that the information relates to. */ #define TPM_PS_PC_11 0x0001 #define TPM_PS_PC_12 0x0002 #define TPM_PS_PDA_12 0x0003 #define TPM_PS_Server_12 0x0004 #define TPM_PS_Mobile_12 0x0005 /* * TPM Basic Structures */ /* * TPM_STRUCT_VER ([TPM_Part2], Section 5.1) * This indicates the version of the structure. */ typedef struct tdTPM_STRUCT_VER { BYTE major; BYTE minor; BYTE revMajor; BYTE revMinor; } TPM_STRUCT_VER; /* * TPM_VERSION ([TPM_Part2], Section 5.3) * This structure provides information relative the version of the TPM. * This structure should only be in use by TPM_GetCapability to provide * the information relative to the TPM. */ typedef struct tdTPM_VERSION { TPM_VERSION_BYTE major; TPM_VERSION_BYTE minor; BYTE revMajor; BYTE revMinor; } TPM_VERSION; #define sizeof_TPM_VERSION(s) (4) /* * TPM_DIGEST ([TPM_Part2], Section 5.4) * The digest value reports the result of a hash operation. * In version 1 the hash algorithm is SHA-1 (20 bytes resp. 160 bits). */ typedef struct tdTPM_DIGEST { BYTE digest[20]; } TPM_DIGEST; /* Redefinitions */ typedef TPM_DIGEST TPM_CHOSENID_HASH; typedef TPM_DIGEST TPM_COMPOSITE_HASH; typedef TPM_DIGEST TPM_DIRVALUE; typedef TPM_DIGEST TPM_HMAC; typedef TPM_DIGEST TPM_PCRVALUE; typedef TPM_DIGEST TPM_AUDITDIGEST; /* * TPM_NONCE ([TPM_Part2], Section 5.5) * A random value that provides protection from replay and other attacks. */ typedef struct tdTPM_NONCE{ BYTE nonce[20]; } TPM_NONCE; /* Redefinitions */ typedef TPM_NONCE TPM_DAA_TPM_SEED; typedef TPM_NONCE TPM_DAA_CONTEXT_SEED; /* * TPM_AUTHDATA ([TPM_Part2], Section 5.6) * Information that is saved or passed to provide proof of ownership of an * entity. For version 1 this area is always 20 bytes. */ typedef BYTE TPM_AUTHDATA[20]; /* Redefinitions */ typedef TPM_AUTHDATA TPM_SECRET; typedef TPM_AUTHDATA TPM_ENCAUTH; /* * TPM_KEY_HANDLE_LIST ([TPM_Part2], Section 5.7) * Structure used to describe the handles of all keys currently * loaded into a TPM. */ typedef struct tdTPM_KEY_HANDLE_LIST { UINT16 loaded; TPM_KEY_HANDLE *handle; } TPM_KEY_HANDLE_LIST; /* * TPM_KEY_USAGE ([TPM_Part2], Section 5.8) * Defines the types of keys that are possible. */ #define TPM_KEY_SIGNING 0x0010 #define TPM_KEY_STORAGE 0x0011 #define TPM_KEY_IDENTITY 0x0012 #define TPM_KEY_AUTHCHANGE 0x0013 #define TPM_KEY_BIND 0x0014 #define TPM_KEY_LEGACY 0x0015 #define TPM_KEY_MIGRATE 0x0016 /* * Encryption Schemes ([TPM_Part2], Section 5.8.1) */ #define TPM_ES_NONE 0x0001 #define TPM_ES_RSAESPKCSv15 0x0002 #define TPM_ES_RSAESOAEP_SHA1_MGF1 0x0003 #define TPM_ES_SYM_CTR 0x0004 #define TPM_ES_SYM_OFB 0x0005 /* * Signature Schemes ([TPM_Part2], Section 5.8.1) */ #define TPM_SS_NONE 0x0001 #define TPM_SS_RSASSAPKCS1v15_SHA1 0x0002 #define TPM_SS_RSASSAPKCS1v15_DER 0x0003 #define TPM_SS_RSASSAPKCS1v15_INFO 0x0004 /* * TPM_AUTH_DATA_USAGE ([TPM_Part2], Section 5.9) * Indication when authorization sessions for an entity are required. */ #define TPM_AUTH_NEVER 0x00 #define TPM_AUTH_ALWAYS 0x01 #define TPM_AUTH_PRIV_USE_ONLY 0x03 /* * TPM_KEY_FLAGS ([TPM_Part2], Section 5.10) * This table defines the meanings of the bits in a TPM_KEY_FLAGS structure. */ #define TPM_KEY_FLAG_REDIRECT 0x00000001 #define TPM_KEY_FLAG_MIGRATABLE 0x00000002 #define TPM_KEY_FLAG_VOLATILE 0x00000004 #define TPM_KEY_FLAG_PCR_IGNORE 0x00000008 #define TPM_KEY_FLAG_AUTHORITY 0x00000010 /* to use with TPM_KEY_DATA only! */ #define TPM_KEY_FLAG_HAS_PCR 0x10000000 #define TPM_KEY_FLAG_MASK 0x0fffffff /* * TPM_CHANGEAUTH_VALIDATE ([TPM_Part2], Section 5.11) * To store the new authorization data and the challenger's nonce. */ typedef struct tdTPM_CHANGEAUTH_VALIDATE { TPM_SECRET newAuthSecret; TPM_NONCE n1; } TPM_CHANGEAUTH_VALIDATE; #define sizeof_TPM_CHANGEAUTH_VALIDATE(s) (20 + 20) /* * TPM_COUNTER_VALUE ([TPM_Part2], Section 5.13) * This structure returns the counter value. * For interoperability, the value size should be 4 bytes. */ #define TPM_TAG_COUNTER_VALUE 0x000E typedef struct tdTPM_COUNTER_VALUE { TPM_STRUCTURE_TAG tag; BYTE label[4]; TPM_ACTUAL_COUNT counter; /* additional, not marshalled data */ TPM_SECRET usageAuth; BOOL valid; } TPM_COUNTER_VALUE; #define sizeof_TPM_COUNTER_VALUE(s) (2 + 4 + 4) #define sizeof_TPM_COUNTER_VALUE2(s) (2 + 4 + 4 + 20 + 1) /* * TPM_SIGN_INFO Structure ([TPM_Part2], Section 5.14) * To provide the mechanism to quote the current values of a list of PCRs. */ #define TPM_TAG_SIGNINFO 0x0005 typedef struct tdTPM_SIGN_INFO { TPM_STRUCTURE_TAG tag; BYTE fixed[4]; TPM_NONCE replay; UINT32 dataLen; BYTE* data; } TPM_SIGN_INFO; #define MAX_MSA_COMPOSITE_ENTRIES 16 /* * TPM_MSA_COMPOSITE ([TPM_Part2], Section 5.15) * Contains an arbitrary number of digests of public keys belonging to * Migration Authorities. */ typedef struct tdTPM_MSA_COMPOSITE { UINT32 MSAlist; TPM_DIGEST migAuthDigest[MAX_MSA_COMPOSITE_ENTRIES]; } TPM_MSA_COMPOSITE; #define sizeof_TPM_MSA_COMPOSITE(s) (4 + s.MSAlist * 20) /* * TPM_CMK_AUTH ([TPM_Part2], Section 5.16) */ typedef struct tdTPM_CMK_AUTH { TPM_DIGEST migrationAuthorityDigest; TPM_DIGEST destinationKeyDigest; TPM_DIGEST sourceKeyDigest; } TPM_CMK_AUTH; #define sizeof_TPM_CMK_AUTH(s) (3 * 20) /* * TPM_CMK_DELEGATE ([TPM_Part2], Section 5.17) * Determine how to respond to delegated requests to manipulate a * restricted-migration key. */ #define TPM_CMK_DELEGATE_SIGNING (1 << 31) #define TPM_CMK_DELEGATE_STORAGE (1 << 30) #define TPM_CMK_DELEGATE_BIND (1 << 29) #define TPM_CMK_DELEGATE_LEGACY (1 << 28) #define TPM_CMK_DELEGATE_MIGRATE (1 << 27) /* bits 26-0 are reserved and must be 0 */ /* * TPM_SELECT_SIZE ([TPM_Part2], Section 5.18) * Indication for the version and size of TPM_SELECTION in TPM_GetCapability. */ typedef struct tdTPM_SELECT_SIZE { BYTE major; BYTE minor; UINT16 reqSize; } TPM_SELECT_SIZE; /* * TPM_CMK_MIGAUTH ([TPM_Part2], Section 5.19) * Structure to keep track of the CMK migration authorization. */ #define TPM_TAG_CMK_MIGAUTH 0x0033 typedef struct tdTPM_CMK_MIGAUTH { TPM_STRUCTURE_TAG tag; TPM_DIGEST msaDigest; TPM_DIGEST pubKeyDigest; } TPM_CMK_MIGAUTH; /* * TPM_CMK_SIGTICKET ([TPM_Part2], Section 5.20) * Structure to keep track of the CMK migration authorization. */ #define TPM_TAG_CMK_SIGTICKET 0x0034 typedef struct tdTPM_CMK_SIGTICKET { TPM_STRUCTURE_TAG tag; TPM_DIGEST verKeyDigest; TPM_DIGEST signedData; } TPM_CMK_SIGTICKET; /* * TPM_CMK_MA_APPROVAL ([TPM_Part2], Section 5.21) * Structure to keep track of the CMK migration authorization. */ #define TPM_TAG_CMK_MA_APPROVAL 0x0035 typedef struct tdTPM_CMK_MA_APPROVAL { TPM_STRUCTURE_TAG tag; TPM_DIGEST migrationAuthorityDigest; } TPM_CMK_MA_APPROVAL; /* * Command Tags ([TPM_Part2], Section 6) * Indicate the construction of the command either as input or as output. */ #define TPM_TAG_RQU_COMMAND 0x00C1 #define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 #define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 #define TPM_TAG_RSP_COMMAND 0x00C4 #define TPM_TAG_RSP_AUTH1_COMMAND 0x00C5 #define TPM_TAG_RSP_AUTH2_COMMAND 0x00C6 /* * Ordinals ([TPM_Part2], Section 17) * The command ordinals provide the index value for each command. */ #define TPM_PROTECTED_COMMAND 0x00000000 #define TPM_UNPROTECTED_COMMAND 0x80000000 #define TPM_CONNECTION_COMMAND 0x40000000 #define TPM_VENDOR_COMMAND 0x20000000 #define TPM_MAIN 0x00 #define TPM_PC 0x01 #define TPM_PDA 0x02 #define TPM_CELL_PHONE 0x03 #define TPM_SERVER 0x04 #define TPM_PROTECTED_ORDINAL (TPM_PROTECTED_COMMAND | TPM_MAIN) #define TPM_UNPROTECTED_ORDINAL (TPM_UNPROTECTED_COMMAND | TPM_MAIN) #define TPM_CONNECTION_ORDINAL (TPM_CONNECTION_COMMAND | TPM_MAIN) #define TPM_ORD_INDEX_MASK 0x0000FFFF #define TPM_ORD_OIAP 10 #define TPM_ORD_OSAP 11 #define TPM_ORD_ChangeAuth 12 #define TPM_ORD_TakeOwnership 13 #define TPM_ORD_ChangeAuthAsymStart 14 #define TPM_ORD_ChangeAuthAsymFinish 15 #define TPM_ORD_ChangeAuthOwner 16 #define TPM_ORD_DSAP 17 #define TPM_ORD_CMK_CreateTicket 18 #define TPM_ORD_CMK_CreateKey 19 #define TPM_ORD_Extend 20 #define TPM_ORD_PCRRead 21 #define TPM_ORD_Quote 22 #define TPM_ORD_Seal 23 #define TPM_ORD_Unseal 24 #define TPM_ORD_DirWriteAuth 25 #define TPM_ORD_DirRead 26 #define TPM_ORD_CMK_CreateBlob 27 #define TPM_ORD_CMK_SetRestrictions 28 #define TPM_ORD_CMK_ApproveMA 29 #define TPM_ORD_UnBind 30 #define TPM_ORD_CreateWrapKey 31 #define TPM_ORD_LoadKey 32 #define TPM_ORD_GetPubKey 33 #define TPM_ORD_EvictKey 34 #define TPM_ORD_KeyControlOwner 35 #define TPM_ORD_CMK_ConvertMigration 36 #define TPM_ORD_MigrateKey 37 #define TPM_ORD_CreateMigrationBlob 40 #define TPM_ORD_DAA_Join 41 #define TPM_ORD_ConvertMigrationBlob 42 #define TPM_ORD_AuthorizeMigrationKey 43 #define TPM_ORD_CreateMaintenanceArchive 44 #define TPM_ORD_LoadMaintenanceArchive 45 #define TPM_ORD_KillMaintenanceFeature 46 #define TPM_ORD_LoadManuMaintPub 47 #define TPM_ORD_ReadManuMaintPub 48 #define TPM_ORD_DAA_Sign 49 #define TPM_ORD_CertifyKey 50 #define TPM_ORD_CertifyKey2 51 #define TPM_ORD_Sign 60 #define TPM_ORD_Sealx 61 #define TPM_ORD_Quote2 62 #define TPM_ORD_SetCapability 63 #define TPM_ORD_ResetLockValue 64 #define TPM_ORD_LoadKey2 65 #define TPM_ORD_GetRandom 70 #define TPM_ORD_StirRandom 71 #define TPM_ORD_SelfTestFull 80 #define TPM_ORD_ContinueSelfTest 83 #define TPM_ORD_GetTestResult 84 #define TPM_ORD_Reset 90 #define TPM_ORD_OwnerClear 91 #define TPM_ORD_DisableOwnerClear 92 #define TPM_ORD_ForceClear 93 #define TPM_ORD_DisableForceClear 94 #define TPM_ORD_GetCapability 101 #define TPM_ORD_GetCapabilityOwner 102 #define TPM_ORD_OwnerSetDisable 110 #define TPM_ORD_PhysicalEnable 111 #define TPM_ORD_PhysicalDisable 112 #define TPM_ORD_SetOwnerInstall 113 #define TPM_ORD_PhysicalSetDeactivated 114 #define TPM_ORD_SetTempDeactivated 115 #define TPM_ORD_SetOperatorAuth 116 #define TPM_ORD_SetOwnerPointer 117 #define TPM_ORD_CreateEndorsementKeyPair 120 #define TPM_ORD_MakeIdentity 121 #define TPM_ORD_ActivateIdentity 122 #define TPM_ORD_ReadPubek 124 #define TPM_ORD_OwnerReadPubek 125 #define TPM_ORD_DisablePubekRead 126 #define TPM_ORD_CreateRevocableEK 127 #define TPM_ORD_RevokeTrust 128 #define TPM_ORD_OwnerReadInternalPub 129 #define TPM_ORD_GetAuditDigest 133 #define TPM_ORD_GetAuditDigestSigned 134 #define TPM_ORD_SetOrdinalAuditStatus 141 #define TPM_ORD_Terminate_Handle 150 #define TPM_ORD_Init 151 #define TPM_ORD_SaveState 152 #define TPM_ORD_Startup 153 #define TPM_ORD_SetRedirection 154 #define TPM_ORD_SHA1Start 160 #define TPM_ORD_SHA1Update 161 #define TPM_ORD_SHA1Complete 162 #define TPM_ORD_SHA1CompleteExtend 163 #define TPM_ORD_FieldUpgrade 170 #define TPM_ORD_SaveKeyContext 180 #define TPM_ORD_LoadKeyContext 181 #define TPM_ORD_SaveAuthContext 182 #define TPM_ORD_LoadAuthContext 183 #define TPM_ORD_SaveContext 184 #define TPM_ORD_LoadContext 185 #define TPM_ORD_FlushSpecific 186 #define TPM_ORD_PCR_Reset 200 #define TPM_ORD_NV_DefineSpace 204 #define TPM_ORD_NV_WriteValue 205 #define TPM_ORD_NV_WriteValueAuth 206 #define TPM_ORD_NV_ReadValue 207 #define TPM_ORD_NV_ReadValueAuth 208 #define TPM_ORD_Delegate_UpdateVerification 209 #define TPM_ORD_Delegate_Manage 210 #define TPM_ORD_Delegate_CreateKeyDelegation 212 #define TPM_ORD_Delegate_CreateOwnerDelegation 213 #define TPM_ORD_Delegate_VerifyDelegation 214 #define TPM_ORD_Delegate_LoadOwnerDelegation 216 #define TPM_ORD_Delegate_ReadAuth 217 #define TPM_ORD_Delegate_ReadTable 219 #define TPM_ORD_CreateCounter 220 #define TPM_ORD_IncrementCounter 221 #define TPM_ORD_ReadCounter 222 #define TPM_ORD_ReleaseCounter 223 #define TPM_ORD_ReleaseCounterOwner 224 #define TPM_ORD_EstablishTransport 230 #define TPM_ORD_ExecuteTransport 231 #define TPM_ORD_ReleaseTransportSigned 232 #define TPM_ORD_GetTicks 241 #define TPM_ORD_TickStampBlob 242 #define TPM_ORD_MAX 256 /* * TCS Ordinals ([TPM_Part2], Section 17.1) * * The TSC ordinals are optional in the main specification. * They are mandatory in the PC Client specification. * * The connection commands manage the TPM's connection to the TBB. */ #define TSC_ORD_PhysicalPresence (10 + TPM_CONNECTION_COMMAND) #define TSC_ORD_ResetEstablishmentBit (11 + TPM_CONNECTION_COMMAND) /* * PCR Structures */ /* * Number of PCRs of the TPM (must be a multiple of eight) */ #define TPM_NUM_PCR 24 /* * TPM_PCR_SELECTION ([TPM_Part2], Section 8.1) * Provides a standard method of specifying a list of PCR registers. * Note: An error is reported if sizeOfSelect > sizeof(pcrSelect). */ typedef struct tdTPM_PCR_SELECTION { UINT16 sizeOfSelect; BYTE pcrSelect[TPM_NUM_PCR/8]; } TPM_PCR_SELECTION; #define sizeof_TPM_PCR_SELECTION(s) (2 + s.sizeOfSelect) /* * TPM_PCR_COMPOSITE ([TPM_Part2], Section 8.2) * The composite structure provides the index and value of the PCR register * to be used when creating the value that SEALS an entity to the composite. */ typedef struct tdTPM_PCR_COMPOSITE { TPM_PCR_SELECTION select; UINT32 valueSize; TPM_PCRVALUE pcrValue[TPM_NUM_PCR]; } TPM_PCR_COMPOSITE; #define sizeof_TPM_PCR_COMPOSITE(s) (sizeof_TPM_PCR_SELECTION(s.select) \ + 4 + s.valueSize) /* * TPM_LOCALITY_SELECTION ([TPM_Part2], Section 8.6) * When used with localityAtCreation only one bit is set and it corresponds * to the locality of the command creating the structure. * When used with localityAtRelease the bits indicate which localities * CAN perform the release. */ typedef BYTE TPM_LOCALITY_SELECTION; /* 5-7 are reserved and must be 0 */ #define TPM_LOC_FOUR (1 << 4) #define TPM_LOC_THREE (1 << 3) #define TPM_LOC_TWO (1 << 2) #define TPM_LOC_ONE (1 << 1) #define TPM_LOC_ZERO (1 << 0) /* * TPM_PCR_INFO ([TPM_Part2], Section 8.3) * Contains the information related to the wrapping of a key or the sealing * of data, to a set of PCRs. * * TPM_PCR_INFO_LONG ([TPM_Part2], Section 8.4) * This structure includes information necessary to properly define the * configuration that creates the blob using the PCR selection. */ #define TPM_TAG_PCR_INFO_LONG 0x0006 typedef struct tdTPM_PCR_INFO { TPM_STRUCTURE_TAG tag; TPM_LOCALITY_SELECTION localityAtCreation; TPM_LOCALITY_SELECTION localityAtRelease; TPM_PCR_SELECTION creationPCRSelection; TPM_PCR_SELECTION releasePCRSelection; TPM_COMPOSITE_HASH digestAtCreation; TPM_COMPOSITE_HASH digestAtRelease; } TPM_PCR_INFO; #define sizeof_TPM_PCR_INFO(s) (2 + 1 + 1 \ + sizeof_TPM_PCR_SELECTION(s.creationPCRSelection) \ + sizeof_TPM_PCR_SELECTION(s.releasePCRSelection) + 20 + 20) /* * TPM_PCR_INFO_SHORT ([TPM_Part2], Section 8.5) * Defines a digest at release when the only information that is necessary * is the release configuration. */ typedef struct tdTPM_PCR_INFO_SHORT { TPM_PCR_SELECTION pcrSelection; TPM_LOCALITY_SELECTION localityAtRelease; TPM_COMPOSITE_HASH digestAtRelease; } TPM_PCR_INFO_SHORT; #define sizeof_TPM_PCR_INFO_SHORT(s) ( \ sizeof_TPM_PCR_SELECTION(s.pcrSelection) + 1 + 20) /* * TPM_PCR_ATTRIBUTES ([TPM_Part2], Section 8.8) * These attributes are available on a per PCR basis. */ typedef struct tdTPM_PCR_ATTRIBUTES { BOOL pcrReset; TPM_LOCALITY_SELECTION pcrExtendLocal; TPM_LOCALITY_SELECTION pcrResetLocal; } TPM_PCR_ATTRIBUTES; #define sizeof_TPM_PCR_ATTRIBUTES(s) (1 + 1 + 1) /* * Storage Structures */ /* * TPM_STORED_DATA ([TPM_Part2], Section 9.1) * TPM_STORED_DATA12 ([TPM_Part2], Section 9.2) * The definition of this structure is necessary to ensure * the enforcement of security properties. */ #define TPM_TAG_STORED_DATA12 0x0016 typedef struct tdTPM_STORED_DATA { TPM_STRUCTURE_TAG tag; TPM_ENTITY_TYPE et; UINT32 sealInfoSize; TPM_PCR_INFO sealInfo; UINT32 encDataSize; BYTE* encData; } TPM_STORED_DATA; #define sizeof_TPM_STORED_DATA(s) (2 + 2 + 4 + s.sealInfoSize \ + 4 + s.encDataSize) #define free_TPM_STORED_DATA(s) { \ if (s.encDataSize > 0) tpm_free(s.encData); } /* * TPM_SEALED_DATA ([TPM_Part2], Section 9.3) * This structure contains confidential information related * to sealed data, including the data itself. */ typedef struct tdTPM_SEALED_DATA { TPM_PAYLOAD_TYPE payload; TPM_SECRET authData; TPM_NONCE tpmProof; TPM_DIGEST storedDigest; UINT32 dataSize; BYTE* data; } TPM_SEALED_DATA; #define sizeof_TPM_SEALED_DATA(s) (1 + 20 + 20 + 20 + 4 + s.dataSize) #define free_TPM_SEALED_DATA(s) { if (s.dataSize > 0) tpm_free(s.data); } /* * TPM_SYMMETRIC_KEY ([TPM_Part2], Section 9.4) * Describes a symmetric key. */ typedef struct tdTPM_SYMMETRIC_KEY { TPM_ALGORITHM_ID algId; TPM_ENC_SCHEME encScheme; UINT16 size; BYTE* data; } TPM_SYMMETRIC_KEY; #define sizeof_TPM_SYMMETRIC_KEY(s) (4 + 2 + 2 + s.size) #define free_TPM_SYMMETRIC_KEY(s) { if (s.size > 0) tpm_free(s.data); } /* * TPM_BOUND_DATA ([TPM_Part2], Section 9.5) * This structure is used by a TPM_UnBind command in a consistency check. */ typedef struct tdTPM_BOUND_DATA { TPM_STRUCT_VER ver; TPM_PAYLOAD_TYPE payload; BYTE* payloadData; } TPM_BOUND_DATA; /* * TPM_KEY complex ([TPM_Part2], Section 10) * The TPA_KEY complex is where all of the information regarding keys * is kept. These structures combine to fully define and protect the * information regarding an asymmetric key. */ /* * TPM_RSA_KEY_PARMS ([TPM_Part2], Section 10.1.1) * This structure describes the parameters of an RSA key. */ typedef struct tdTPM_RSA_KEY_PARMS { UINT32 keyLength; UINT32 numPrimes; UINT32 exponentSize; BYTE* exponent; } TPM_RSA_KEY_PARMS; #define sizeof_TPM_RSA_KEY_PARMS(s) (4 + 4 + 4 + s.exponentSize) #define free_TPM_RSA_KEY_PARMS(s) { \ if (s.exponentSize > 0) tpm_free(s.exponent); } /* * TPM_SYMMETRIC_KEY_PARMS ([TPM_Part2], Section 10.1.2) * This structure describes the parameters for symmetric algorithms. */ typedef struct tdTPM_SYMMETRIC_KEY_PARMS { UINT32 keyLength; UINT32 blockSize; UINT32 ivSize; BYTE* IV; } TPM_SYMMETRIC_KEY_PARMS; #define sizeof_TPM_SYMMETRIC_KEY_PARMS(s) (4 + 4 + 4 + s.ivSize) #define free_TPM_SYMMETRIC_KEY_PARMS(s) { if (s.ivSize > 0) tpm_free(s.IV); } /* * TPM_KEY_PARMS ([TPM_Part2], Section 10.1) * This provides a standard mechanism to define the parameters used to * generate a key pair. */ typedef struct tdTPM_KEY_PARMS { TPM_ALGORITHM_ID algorithmID; TPM_ENC_SCHEME encScheme; TPM_SIG_SCHEME sigScheme; UINT32 parmSize; union { BYTE* raw; TPM_RSA_KEY_PARMS rsa; TPM_SYMMETRIC_KEY_PARMS skp; } parms; } TPM_KEY_PARMS; #define sizeof_TPM_KEY_PARMS(s) (4 + 2 + 2 + 4 + s.parmSize) #define free_TPM_KEY_PARMS(s) { if (s.parmSize > 0) { \ switch (s.algorithmID) { \ case TPM_ALG_RSA: free_TPM_RSA_KEY_PARMS(s.parms.rsa); break; \ case TPM_ALG_DES: case TPM_ALG_3DES: \ case TPM_ALG_AES192: case TPM_ALG_AES256: \ free_TPM_SYMMETRIC_KEY_PARMS(s.parms.skp); break; \ default: tpm_free(s.parms.raw); } } } /* * TPM_STORE_PUBKEY ([TPM_Part2], Section 10.4) * This structure can be used in conjunction with a corresponding * TPM_KEY_PARMS to construct a public key which can be unambiguously used. */ typedef struct tdTPM_STORE_PUBKEY { UINT32 keyLength; BYTE* key; } TPM_STORE_PUBKEY; #define sizeof_TPM_STORE_PUBKEY(s) (4 + s.keyLength) #define free_TPM_STORE_PUBKEY(s) { if (s.keyLength > 0) tpm_free(s.key); } /* * TPM_KEY ([TPM_Part2], Section 10.2) * The TPM_KEY structure provides a mechanism to transport the entire * asymmetric key pair. The private portion of the key is always encrypted. * The TPM_KEY12 ([TPM_Part2], Section 10.3) structure uses the new * TPM_PCR_INFO_LONG structures and the new structure tagging. */ #define TPM_TAG_KEY12 0x0028 typedef struct tdTPM_KEY { TPM_STRUCTURE_TAG tag; UINT16 fill; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; UINT32 PCRInfoSize; TPM_PCR_INFO PCRInfo; TPM_STORE_PUBKEY pubKey; UINT32 encDataSize; BYTE* encData; } TPM_KEY; #define sizeof_TPM_KEY(s) (4 + 2 + 4 + 1 \ + sizeof_TPM_KEY_PARMS(s.algorithmParms) \ + 4 + s.PCRInfoSize + sizeof_TPM_STORE_PUBKEY(s.pubKey) \ + 4 + s.encDataSize) #define free_TPM_KEY(s) { if (s.encDataSize > 0) tpm_free(s.encData); \ free_TPM_KEY_PARMS(s.algorithmParms); free_TPM_STORE_PUBKEY(s.pubKey); } /* * TPM_PUBKEY ([TPM_Part2], Section 10.5) * Public portion of an asymmetric key pair. */ typedef struct tdTPM_PUBKEY { TPM_KEY_PARMS algorithmParms; TPM_STORE_PUBKEY pubKey; } TPM_PUBKEY; #define sizeof_TPM_PUBKEY(s) (sizeof_TPM_KEY_PARMS(s.algorithmParms) \ + sizeof_TPM_STORE_PUBKEY(s.pubKey)) #define free_TPM_PUBKEY(s) { free_TPM_KEY_PARMS(s.algorithmParms); \ free_TPM_STORE_PUBKEY(s.pubKey); } /* * TPM_STORE_PRIVKEY ([TPM_Part2], Section 10.7) * This structure can be used in conjunction with a corresponding TPM_PUBKEY * to construct a private key which can be unambiguously used. */ typedef struct tdTPM_STORE_PRIVKEY { UINT32 keyLength; BYTE* key; } TPM_STORE_PRIVKEY; #define sizeof_TPM_STORE_PRIVKEY(s) (4 + s.keyLength) #define free_TPM_STORE_PRIVKEY(s) { if (s.keyLength > 0) tpm_free(s.key); } /* * TPM_STORE_ASYMKEY ([TPM_Part2], Section 10.6) * The TPM_STORE_ASYMKEY structure provides the area to identify the * confidential information related to a key. */ typedef struct tdTPM_STORE_ASYMKEY { TPM_PAYLOAD_TYPE payload; TPM_SECRET usageAuth; TPM_SECRET migrationAuth; TPM_DIGEST pubDataDigest; TPM_STORE_PRIVKEY privKey; } TPM_STORE_ASYMKEY; #define sizeof_TPM_STORE_ASYMKEY(s) (1 + 20 + 20 + 20 \ + sizeof_TPM_STORE_PRIVKEY(s.privKey)) #define free_TPM_STORE_ASYMKEY(s) { free_TPM_STORE_PRIVKEY(s.privKey); } /* * TPM_MIGRATE_ASYMKEY ([TPM_Part2], Section 10.8) * The TPM_MIGRATE_ASYMKEY structure provides the area to identify the private * key factors of a asymmetric key while the key is migrating between TPM's. */ typedef struct tdTPM_MIGRATE_ASYMKEY { TPM_PAYLOAD_TYPE payload; TPM_SECRET usageAuth; TPM_DIGEST pubDataDigest; UINT32 partPrivKeyLen; BYTE *partPrivKey; } TPM_MIGRATE_ASYMKEY; #define sizeof_TPM_MIGRATE_ASYMKEY(s) (1 + 20 + 20 + 4 + s.partPrivKeyLen) #define free_TPM_MIGRATE_ASYMKEY(s) { tpm_free(s.partPrivKey); } /* * TPM_MIGRATIONKEYAUTH ([TPM_Part2], Section 5.12) * Provides the proof that the associated public key has authorization to * be a migration key. */ typedef struct tdTPM_MIGRATIONKEYAUTH { TPM_PUBKEY migrationKey; TPM_MIGRATE_SCHEME migrationScheme; TPM_DIGEST digest; } TPM_MIGRATIONKEYAUTH; #define sizeof_TPM_MIGRATIONKEYAUTH(s) (sizeof_TPM_PUBKEY(s.migrationKey) \ + 2 + 20) #define free_TPM_MIGRATIONKEYAUTH(s) { free_TPM_PUBKEY(s.migrationKey); } /* * TPM_KEY_CONTROL ([TPM_Part2], Section 10.9) * Attributes that can control various aspects of key usage and manipulation. */ /* 31:-1 reserved and must be 0 */ #define TPM_KEY_CONTROL_OWNER_EVICT (1 << 0) /* * Signed Structures */ /* * TPM_AUTH ([TPM_Part1], Section ??.?) * Authorization Protocol Input/Output Parameter */ typedef struct tdTPM_AUTH { TPM_AUTHHANDLE authHandle; TPM_NONCE nonceEven; TPM_NONCE nonceOdd; BOOL continueAuthSession; TPM_AUTHDATA auth; /* additional NOT marshalled parameters */ TPM_SECRET secret; BYTE digest[20]; TPM_COMMAND_CODE ordinal; } TPM_AUTH; /* * TPM_CERTIFY_INFO Structure ([TPM_Part2], Section 11.1) * TPM_CERTIFY_INFO2 Structure ([TPM_Part2], Section 11.2) * This structure provides the mechanism to provide a signature with a TPM * identity key on information that describes that key. */ #define TPM_TAG_CERTIFY_INFO2 0x0029 typedef struct tdTPM_CERTIFY_INFO { TPM_STRUCTURE_TAG tag; BYTE fill; TPM_PAYLOAD_TYPE payloadType; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; TPM_DIGEST pubkeyDigest; TPM_NONCE data; BOOL parentPCRStatus; UINT32 PCRInfoSize; TPM_PCR_INFO PCRInfo; UINT32 migrationAuthoritySize; BYTE* migrationAuthority; } TPM_CERTIFY_INFO; #define sizeof_TPM_CERTIFY_INFO(s) (4 + 2 + 4 + 1 + \ sizeof_TPM_KEY_PARMS(s.algorithmParms) + 20 + 20 + 1 + 4 \ + s.PCRInfoSize \ + (s.tag == TPM_TAG_CERTIFY_INFO2 ? 4 + s.migrationAuthoritySize : 0)) #define free_TPM_CERTIFY_INFO(s) { free_TPM_KEY_PARMS(s.algorithmParms); \ if (s.migrationAuthoritySize > 0) tpm_free(s.migrationAuthority); } /* * TPM_QUOTE_INFO Structure ([TPM_Part2], Section 11.3) * This structure provides the mechanism for the TPM to quote the * current values of a list of PCRs. */ typedef struct tdTPM_QUOTE_INFO { TPM_STRUCT_VER version; BYTE fixed[4]; TPM_COMPOSITE_HASH digestValue; TPM_NONCE externalData; } TPM_QUOTE_INFO; /* * TPM_QUOTE_INFO2 Structure ([TPM_Part2], Section 11.4) * This structure provides the mechanism for the TPM to quote the * current values of a list of PCRs. */ #define TPM_TAG_QUOTE_INFO2 0x0036 typedef struct tdTPM_QUOTE_INFO2 { TPM_STRUCTURE_TAG tag; BYTE fixed[4]; TPM_NONCE externalData; TPM_PCR_INFO_SHORT infoShort; } TPM_QUOTE_INFO2; #define sizeof_TPM_QUOTE_INFO2(s) (2 + 4 + 20 + \ sizeof_TPM_PCR_INFO_SHORT(s.infoShort)) /* * Identity Structures */ /* * TPM_EK_BLOB ([TPM_Part2], Section 12.1) * This structure provides a wrapper to each type of structure that * will be in use when the endorsement key is in use. */ #define TPM_TAG_EK_BLOB 0x000C typedef struct tdTPM_EK_BLOB { TPM_STRUCTURE_TAG tag; TPM_EK_TYPE ekType; UINT32 blobSize; BYTE* blob; } TPM_EK_BLOB; /* * TPM_EK_BLOB_ACTIVATE ([TPM_Part2], Section 12.2) * This structure contains the symmetric key to encrypt the identity * credential. This structure always is contained in a TPM_EK_BLOB. */ #define TPM_TAG_EK_BLOB_ACTIVATE 0x002B typedef struct tdTPM_EK_BLOB_ACTIVATE { TPM_STRUCTURE_TAG tag; TPM_SYMMETRIC_KEY sessionKey; TPM_DIGEST idDigest; TPM_PCR_INFO_SHORT pcrInfo; } TPM_EK_BLOB_ACTIVATE; /* * TPM_EK_BLOB_AUTH ([TPM_Part2], Section 12.3) * This structure contains the symmetric key to encrypt the identity * credential. This structure always is contained in a TPM_EK_BLOB. */ #define TPM_TAG_EK_BLOB_AUTH 0x000D typedef struct tdTPM_EK_BLOB_AUTH { TPM_STRUCTURE_TAG tag; TPM_SECRET authValue; } TPM_EK_BLOB_AUTH; /* * TPM_IDENTITY_CONTENTS ([TPM_Part2], Section 12.5) * TPM_MakeIdentity uses this structure and the signature of this structure * goes to a privacy CA during the certification process. */ typedef struct tdTPM_IDENTITY_CONTENTS { TPM_STRUCT_VER ver; UINT32 ordinal; TPM_CHOSENID_HASH labelPrivCADigest; TPM_PUBKEY identityPubKey; } TPM_IDENTITY_CONTENTS; #define sizeof_TPM_IDENTITY_CONTENTS(s) (4 + 4 + 20 + \ sizeof_TPM_PUBKEY(s.identityPubKey)) /* * TPM_IDENTITY_REQ ([TPM_Part2], Section 12.6) * This structure is sent by the TSS to the Privacy CA to create the * identity credential. This structure is informative only. */ /* * TPM_IDENTITY_PROOF ([TPM_Part2], Section 12.7) * Structure in use during the AIK credential process. */ /* * TPM_ASYM_CA_CONTENTS ([TPM_Part2], Section 12.8) * Contains the symmetric key to encrypt the identity credential. */ typedef struct tdTPM_ASYM_CA_CONTENTS { TPM_SYMMETRIC_KEY sessionKey; TPM_DIGEST idDigest; } TPM_ASYM_CA_CONTENTS; /* * TPM_SYM_CA_ATTESTATION ([TPM_Part2], Section 12.9) * This structure returned by the Privacy CA with the encrypted * identity credential. */ /* * Tick Structures */ /* * TPM_CURRENT_TICKS ([TPM_Part2], Section 15.1) * This structure holds the current number of time ticks in the TPM. */ #define TPM_TAG_CURRENT_TICKS 0x0014 typedef struct tdTPM_CURRENT_TICKS { TPM_STRUCTURE_TAG tag; UINT64 currentTicks; UINT16 tickRate; TPM_NONCE tickNonce; } TPM_CURRENT_TICKS; #define sizeof_TPM_CURRENT_TICKS(s) (2 + 8 + 2 + 20) /* * Transport Structures */ /* * TPM_TRANSPORT_PUBLIC ([TPM_Part2], Section 13.1) * The public information relative to a transport session. */ #define TPM_TAG_TRANSPORT_PUBLIC 0x001E typedef struct tdTPM_TRANSPORT_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_TRANSPORT_ATTRIBUTES transAttributes; TPM_ALGORITHM_ID algID; TPM_ENC_SCHEME encScheme; } TPM_TRANSPORT_PUBLIC; #define sizeof_TPM_TRANSPORT_PUBLIC(s) (2 + 4 + 4 + 2) /* TPM_TRANSPORT_ATTRIBUTES Definitions ([TPM_Part2], Section 13.1.1) */ #define TPM_TRANSPORT_ENCRYPT 0x00000001 #define TPM_TRANSPORT_LOG 0x00000002 #define TPM_TRANSPORT_EXCLUSIVE 0x00000004 /* * TPM_TRANSPORT_INTERNAL ([TPM_Part2], Section 13.2) * The internal information regarding transport session. */ #define TPM_TAG_TRANSPORT_INTERNAL 0x000F typedef struct tdTPM_TRANSPORT_INTERNAL { TPM_STRUCTURE_TAG tag; TPM_AUTHDATA authData; TPM_TRANSPORT_PUBLIC transPublic; TPM_TRANSHANDLE transHandle; TPM_NONCE transNonceEven; TPM_DIGEST transDigest; } TPM_TRANSPORT_INTERNAL; #define sizeof_TPM_TRANSPORT_INTERNAL(s) (2 + 20 + 4 + 20 + 20 \ + sizeof_TPM_TRANSPORT_PUBLIC(s.transPublic)) /* * TPM_TRANSPORT_LOG_IN structure ([TPM_Part2], Section 13.3) * This structure is in use for input log calculations. */ #define TPM_TAG_TRANSPORT_LOG_IN 0x0010 typedef struct tdTPM_TRANSPORT_LOG_IN { TPM_STRUCTURE_TAG tag; TPM_DIGEST parameters; TPM_DIGEST pubKeyHash; } TPM_TRANSPORT_LOG_IN; #define sizeof_TPM_TRANSPORT_LOG_IN(s) (2 + 20 + 20) /* * TPM_TRANSPORT_LOG_OUT structure ([TPM_Part2], Section 13.4) * This structure is in use for output log calculations. * This structure is in use for the INPUT logging during releaseTransport. */ #define TPM_TAG_TRANSPORT_LOG_OUT 0x0011 typedef struct tdTPM_TRANSPORT_LOG_OUT { TPM_STRUCTURE_TAG tag; TPM_CURRENT_TICKS currentTicks; TPM_DIGEST parameters; TPM_MODIFIER_INDICATOR locality; } TPM_TRANSPORT_LOG_OUT; #define sizeof_TPM_TRANSPORT_LOG_OUT(s) (2 + 20 + 4 \ + sizeof_TPM_CURRENT_TICKS(s.currentTicks)) /* * TPM_TRANSPORT_AUTH structure ([TPM_Part2], Section 13.5) * Provides the validation for the encrypted authorization value. */ #define TPM_TAG_TRANSPORT_AUTH 0x001D typedef struct tdTPM_TRANSPORT_AUTH { TPM_STRUCTURE_TAG tag; TPM_AUTHDATA authData; } TPM_TRANSPORT_AUTH; #define sizeof_TPM_TRANSPORT_AUTH(s) (2 + 20) /* * Audit Structures */ /* * TPM_AUDIT_EVENT_IN structure ([TPM_Part2], Section 14.1) * This structure provides the auditing of the command upon receipt of * the command. It provides the information regarding the input parameters. */ #define TPM_TAG_AUDIT_EVENT_IN 0x0012 typedef struct tdTPM_AUDIT_EVENT_IN { TPM_STRUCTURE_TAG tag; TPM_DIGEST inputParms; TPM_COUNTER_VALUE auditCount; } TPM_AUDIT_EVENT_IN; #define sizeof_TPM_AUDIT_EVENT_IN(s) (2 + 20 \ + sizeof_TPM_COUNTER_VALUE(s.auditCount)) /* * TPM_AUDIT_EVENT_OUT structure ([TPM_Part2], Section 14.2) * This structure reports the results of the command execution. * It includes the return code and the output parameters. */ #define TPM_TAG_AUDIT_EVENT_OUT 0x0013 typedef struct tdTPM_AUDIT_EVENT_OUT { TPM_STRUCTURE_TAG tag; TPM_DIGEST outputParms; TPM_COUNTER_VALUE auditCount; } TPM_AUDIT_EVENT_OUT; #define sizeof_TPM_AUDIT_EVENT_OUT(s) (2 + 20 \ + sizeof_TPM_COUNTER_VALUE(s.auditCount)) /* * TPM Return Codes ([TPM_Part2], Section 16) */ #define TPM_NON_FATAL 0x00000800 #define TPM_BASE 0x00000000 #define TPM_SUCCESS (TPM_BASE + 0) #define TPM_AUTHFAIL (TPM_BASE + 1) #define TPM_BADINDEX (TPM_BASE + 2) #define TPM_BAD_PARAMETER (TPM_BASE + 3) #define TPM_AUDITFAILURE (TPM_BASE + 4) #define TPM_CLEAR_DISABLED (TPM_BASE + 5) #define TPM_DEACTIVATED (TPM_BASE + 6) #define TPM_DISABLED (TPM_BASE + 7) #define TPM_DISABLED_CMD (TPM_BASE + 8) #define TPM_FAIL (TPM_BASE + 9) #define TPM_BAD_ORDINAL (TPM_BASE + 10) #define TPM_INSTALL_DISABLED (TPM_BASE + 11) #define TPM_INVALID_KEYHANDLE (TPM_BASE + 12) #define TPM_KEYNOTFOUND (TPM_BASE + 13) #define TPM_INAPPROPRIATE_ENC (TPM_BASE + 14) #define TPM_MIGRATEFAIL (TPM_BASE + 15) #define TPM_INVALID_PCR_INFO (TPM_BASE + 16) #define TPM_NOSPACE (TPM_BASE + 17) #define TPM_NOSRK (TPM_BASE + 18) #define TPM_NOTSEALED_BLOB (TPM_BASE + 19) #define TPM_OWNER_SET (TPM_BASE + 20) #define TPM_RESOURCES (TPM_BASE + 21) #define TPM_SHORTRANDOM (TPM_BASE + 22) #define TPM_SIZE (TPM_BASE + 23) #define TPM_WRONGPCRVAL (TPM_BASE + 24) #define TPM_BAD_PARAM_SIZE (TPM_BASE + 25) #define TPM_SHA_THREAD (TPM_BASE + 26) #define TPM_SHA_ERROR (TPM_BASE + 27) #define TPM_FAILEDSELFTEST (TPM_BASE + 28) #define TPM_AUTH2FAIL (TPM_BASE + 29) #define TPM_BADTAG (TPM_BASE + 30) #define TPM_IOERROR (TPM_BASE + 31) #define TPM_ENCRYPT_ERROR (TPM_BASE + 32) #define TPM_DECRYPT_ERROR (TPM_BASE + 33) #define TPM_INVALID_AUTHHANDLE (TPM_BASE + 34) #define TPM_NO_ENDORSEMENT (TPM_BASE + 35) #define TPM_INVALID_KEYUSAGE (TPM_BASE + 36) #define TPM_WRONG_ENTITYTYPE (TPM_BASE + 37) #define TPM_INVALID_POSTINIT (TPM_BASE + 38) #define TPM_INAPPROPRIATE_SIG (TPM_BASE + 39) #define TPM_BAD_KEY_PROPERTY (TPM_BASE + 40) #define TPM_BAD_MIGRATION (TPM_BASE + 41) #define TPM_BAD_SCHEME (TPM_BASE + 42) #define TPM_BAD_DATASIZE (TPM_BASE + 43) #define TPM_BAD_MODE (TPM_BASE + 44) #define TPM_BAD_PRESENCE (TPM_BASE + 45) #define TPM_BAD_VERSION (TPM_BASE + 46) #define TPM_NO_WRAP_TRANSPORT (TPM_BASE + 47) #define TPM_AUDITFAIL_UNSUCCESSFUL (TPM_BASE + 48) #define TPM_AUDITFAIL_SUCCESSFUL (TPM_BASE + 49) #define TPM_NOTRESETABLE (TPM_BASE + 50) #define TPM_NOTLOCAL (TPM_BASE + 51) #define TPM_BAD_TYPE (TPM_BASE + 52) #define TPM_INVALID_RESOURCE (TPM_BASE + 53) #define TPM_NOTFIPS (TPM_BASE + 54) #define TPM_INVALID_FAMILY (TPM_BASE + 55) #define TPM_NO_NV_PERMISSION (TPM_BASE + 56) #define TPM_REQUIRES_SIGN (TPM_BASE + 57) #define TPM_KEY_NOTSUPPORTED (TPM_BASE + 58) #define TPM_AUTH_CONFLICT (TPM_BASE + 59) #define TPM_AREA_LOCKED (TPM_BASE + 60) #define TPM_BAD_LOCALITY (TPM_BASE + 61) #define TPM_READ_ONLY (TPM_BASE + 62) #define TPM_PER_NOWRITE (TPM_BASE + 63) #define TPM_FAMILYCOUNT (TPM_BASE + 64) #define TPM_WRITE_LOCKED (TPM_BASE + 65) #define TPM_BAD_ATTRIBUTES (TPM_BASE + 66) #define TPM_INVALID_STRUCTURE (TPM_BASE + 67) #define TPM_KEY_OWNER_CONTROL (TPM_BASE + 68) #define TPM_BAD_COUNTER (TPM_BASE + 69) #define TPM_NOT_FULLWRITE (TPM_BASE + 70) #define TPM_CONTEXT_GAP (TPM_BASE + 71) #define TPM_MAXNVWRITES (TPM_BASE + 72) #define TPM_NOOPERATOR (TPM_BASE + 73) #define TPM_RESOURCEMISSING (TPM_BASE + 74) #define TPM_DELEGATE_LOCK (TPM_BASE + 75) #define TPM_DELEGATE_FAMILY (TPM_BASE + 76) #define TPM_DELEGATE_ADMIN (TPM_BASE + 77) #define TPM_TRANSPORT_NOTEXCLUSIVE (TPM_BASE + 78) #define TPM_OWNER_CONTROL (TPM_BASE + 79) #define TPM_DAA_RESOURCES (TPM_BASE + 80) #define TPM_DAA_INPUT_DATA0 (TPM_BASE + 81) #define TPM_DAA_INPUT_DATA1 (TPM_BASE + 82) #define TPM_DAA_ISSUER_SETTINGS (TPM_BASE + 83) #define TPM_DAA_TPM_SETTINGS (TPM_BASE + 84) #define TPM_DAA_STAGE (TPM_BASE + 85) #define TPM_DAA_ISSUER_VALIDITY (TPM_BASE + 86) #define TPM_DAA_WRONG_W (TPM_BASE + 87) #define TPM_BAD_HANDLE (TPM_BASE + 88) #define TPM_BAD_DELEGATE (TPM_BASE + 89) #define TPM_BADCONTEXT (TPM_BASE + 90) #define TPM_TOOMANYCONTEXTS (TPM_BASE + 91) #define TPM_MA_TICKET_SIGNATURE (TPM_BASE + 92) #define TPM_MA_DESTINATION (TPM_BASE + 93) #define TPM_MA_SOURCE (TPM_BASE + 94) #define TPM_MA_AUTHORITY (TPM_BASE + 95) #define TPM_PERMANENTEK (TPM_BASE + 97) #define TPM_BAD_SIGNATURE (TPM_BASE + 98) #define TPM_NOCONTEXTSPACE (TPM_BASE + 99) #define TPM_RETRY (TPM_BASE + TPM_NON_FATAL) #define TPM_NEEDS_SELFTEST (TPM_BASE + TPM_NON_FATAL + 1) #define TPM_DOING_SELFTEST (TPM_BASE + TPM_NON_FATAL + 2) #define TPM_DEFEND_LOCK_RUNNING (TPM_BASE + TPM_NON_FATAL + 3) /* * NV Storage Structures */ /* * Required TPM_NV_INDEX values ([TPM_Part2], Section 19.1.1) * The required index values must be found on each TPM regardless * of platform. These areas are always present and do not require * a TPM_NV_DefineSpace command to allocate. */ #define TPM_NV_INDEX_LOCK 0xFFFFFFFF #define TPM_NV_INDEX0 0x00000000 #define TPM_NV_INDEX_DIR 0x10000001 #define TPM_NV_INDEX_T (1 << 31) #define TPM_NV_INDEX_P (1 << 30) #define TPM_NV_INDEX_U (1 << 29) #define TPM_NV_INDEX_D (1 << 28) /* * Reserved Index values ([TPM_Part2], Section 19.1.2) * The reserved values are defined to avoid index collisions. These * values are not in each and every TPM. */ #define TPM_NV_INDEX_EKCert 0x0000F000 #define TPM_NV_INDEX_TPM_CC 0x0000F001 #define TPM_NV_INDEX_PlatformCert 0x0000F002 #define TPM_NV_INDEX_Platform_CC 0x0000F003 #define TPM_NV_INDEX_TRIAL 0x0000F004 /* * TPM_NV_ATTRIBUTES ([TPM_Part2], Section 19.2) * This structure allows the TPM to keep track of the data and * permissions to manipulate the area. */ #define TPM_TAG_NV_ATTRIBUTES 0x0017 typedef struct tdTPM_NV_ATTRIBUTES { TPM_STRUCTURE_TAG tag; UINT32 attributes; } TPM_NV_ATTRIBUTES; #define TPM_NV_PER_READ_STCLEAR (1 << 31) /* bits 30-19 are reserved and must be 0 */ #define TPM_NV_PER_AUTHREAD (1 << 18) #define TPM_NV_PER_OWNERREAD (1 << 17) #define TPM_NV_PER_PPREAD (1 << 16) #define TPM_NV_PER_GLOBALLOCK (1 << 15) #define TPM_NV_PER_WRITE_STCLEAR (1 << 14) #define TPM_NV_PER_WRITEDEFINE (1 << 13) #define TPM_NV_PER_WRITEALL (1 << 12) /* bits 11-3 are reserved and must be 0 */ #define TPM_NV_PER_AUTHWRITE (1 << 2) #define TPM_NV_PER_OWNERWRITE (1 << 1) #define TPM_NV_PER_PPWRITE (1 << 0) /* * TPM_NV_DATA_PUBLIC ([TPM_Part2], Section 19.3) * Represents the public description and controls on the NV area. */ #define TPM_TAG_NV_DATA_PUBLIC 0x0018 typedef struct tdTPM_NV_DATA_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_NV_INDEX nvIndex; TPM_PCR_INFO_SHORT pcrInfoRead; TPM_PCR_INFO_SHORT pcrInfoWrite; TPM_NV_ATTRIBUTES permission; BOOL bReadSTClear; BOOL bWriteSTClear; BOOL bWriteDefine; UINT32 dataSize; } TPM_NV_DATA_PUBLIC; #define sizeof_TPM_NV_DATA_PUBLIC(s) (2 + 4 + 6 + 1 + 1 + 1 + 4 \ + sizeof_TPM_PCR_INFO_SHORT(s.pcrInfoRead) \ + sizeof_TPM_PCR_INFO_SHORT(s.pcrInfoWrite)) /* * TPM_NV_DATA_SENSITIVE ([TPM_Part2], Section 19.4) * This is an internal structure that the TPM uses to keep the actual * NV data and the controls regarding the area. */ #define TPM_TAG_NV_DATA_SENSITIVE 0x0019 typedef struct tdTPM_NV_DATA_SENSITIVE { TPM_STRUCTURE_TAG tag; TPM_NV_DATA_PUBLIC pubInfo; TPM_AUTHDATA authValue; UINT32 dataIndex; /* additional data */ BOOL valid; } TPM_NV_DATA_SENSITIVE; #define sizeof_TPM_NV_DATA_SENSITIVE(s) (2 \ + sizeof_TPM_NV_DATA_PUBLIC(s.pubInfo) + 20 + 4) /* * Max NV Size ([TPM_Part2], Section 19.5) * This is a value where the minimum value is set by the platform * specific specification. The TPM vendor can design a TPM with a * size that is larger than the minimum. */ #define TPM_MAX_NV_SIZE 4096 /* * Delegate Structures */ /* * Delegate Definitions ([TPM_Part2], Section 20.2) * The delegations are in a 64-bit field. Each bit describes a capability * that the TPM Owner or an authorized key user can delegate to a trusted * process by setting that bit. Each delegation bit setting is independent * of any other delegation bit setting in a row. */ #define TPM_DEL_OWNER_BITS 0x00000001 #define TPM_DEL_KEY_BITS 0x00000002 #define TPM_TAG_DELEGATIONS 0x001A typedef struct tdTPM_DELEGATIONS { TPM_STRUCTURE_TAG tag; UINT32 delegateType; UINT32 per1; UINT32 per2; } TPM_DELEGATIONS; #define sizeof_TPM_DELEGATIONS(s) (2 + 4 + 4 + 4) /* * Owner Permission Settings ([TPM_Part2], Section 20.2.1) * Defines the order of bits in the permission array. */ /* Per1 bits */ /* 31 reserved and must be 0 */ #define TPM_DELEGATE_SetOrdinalAuditStatus (1 << 30) #define TPM_DELEGATE_DirWriteAuth (1 << 29) #define TPM_DELEGATE_CMK_ApproveMA (1 << 28) #define TPM_DELEGATE_NV_WriteValue (1 << 27) #define TPM_DELEGATE_CMK_CreateTicket (1 << 26) #define TPM_DELEGATE_NV_ReadValue (1 << 25) #define TPM_DELEGATE_Delegate_LoadOwnerDelegation (1 << 24) #define TPM_DELEGATE_DAA_Join (1 << 23) #define TPM_DELEGATE_AuthorizeMigrationKey (1 << 22) #define TPM_DELEGATE_CreateMaintenanceArchive (1 << 21) #define TPM_DELEGATE_LoadMaintenanceArchive (1 << 20) #define TPM_DELEGATE_KillMaintenanceFeature (1 << 19) #define TPM_DELEGATE_OwnerReadInternalPub (1 << 18) #define TPM_DELEGATE_ResetLockValue (1 << 17) #define TPM_DELEGATE_OwnerClear (1 << 16) #define TPM_DELEGATE_DisableOwnerClear (1 << 15) #define TPM_DELEGATE_NV_DefineSpace (1 << 14) #define TPM_DELEGATE_OwnerSetDisable (1 << 13) #define TPM_DELEGATE_SetCapability (1 << 12) #define TPM_DELEGATE_MakeIdentity (1 << 11) #define TPM_DELEGATE_ActivateIdentity (1 << 10) #define TPM_DELEGATE_OwnerReadPubek (1 << 9) #define TPM_DELEGATE_DisablePubekRead (1 << 8) #define TPM_DELEGATE_SetRedirection (1 << 7) #define TPM_DELEGATE_FieldUpgrade (1 << 6) #define TPM_DELEGATE_Delegate_UpdateVerification (1 << 5) #define TPM_DELEGATE_CreateCounter (1 << 4) #define TPM_DELEGATE_ReleaseCounterOwner (1 << 3) #define TPM_DELEGATE_Delegate_Manage (1 << 2) #define TPM_DELEGATE_Delegate_CreateOwnerDelegation (1 << 1) #define TPM_DELEGATE_DAA_Sign (1 << 0) /* Per2 bits */ /* 31-0 reserved and must be 0 */ /* * Key Permission settings ([TPM_Part2], Section 20.2.3) * Defines the order of bits in the permission array. */ /* Per1 bits */ /* 31-29 reserved and must be 0 */ #define TPM_KEY_DELEGATE_CMK_ConvertMigration (1 << 28) #define TPM_KEY_DELEGATE_TickStampBlob (1 << 27) #define TPM_KEY_DELEGATE_ChangeAuthAsymStart (1 << 26) #define TPM_KEY_DELEGATE_ChangeAuthAsymFinish (1 << 25) #define TPM_KEY_DELEGATE_CMK_CreateKey (1 << 24) #define TPM_KEY_DELEGATE_MigrateKey (1 << 23) #define TPM_KEY_DELEGATE_LoadKey2 (1 << 22) #define TPM_KEY_DELEGATE_EstablishTransport (1 << 21) #define TPM_KEY_DELEGATE_ReleaseTransportSigned (1 << 20) #define TPM_KEY_DELEGATE_Quote2 (1 << 19) #define TPM_KEY_DELEGATE_Sealx (1 << 18) #define TPM_KEY_DELEGATE_MakeIdentity (1 << 17) #define TPM_KEY_DELEGATE_ActivateIdentity (1 << 16) #define TPM_KEY_DELEGATE_GetAuditDigestSigned (1 << 15) #define TPM_KEY_DELEGATE_Sign (1 << 14) #define TPM_KEY_DELEGATE_CertifyKey2 (1 << 13) #define TPM_KEY_DELEGATE_CertifyKey (1 << 12) #define TPM_KEY_DELEGATE_CreateWrapKey (1 << 11) #define TPM_KEY_DELEGATE_CMK_CreateBlob (1 << 10) #define TPM_KEY_DELEGATE_CreateMigrationBlob (1 << 9) #define TPM_KEY_DELEGATE_ConvertMigrationBlob (1 << 8) #define TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation (1 << 7) #define TPM_KEY_DELEGATE_ChangeAuth (1 << 6) #define TPM_KEY_DELEGATE_GetPubKey (1 << 5) #define TPM_KEY_DELEGATE_Unbind (1 << 4) #define TPM_KEY_DELEGATE_Quote (1 << 3) #define TPM_KEY_DELEGATE_Unseal (1 << 2) #define TPM_KEY_DELEGATE_Seal (1 << 1) #define TPM_KEY_DELEGATE_LoadKey (1 << 0) /* Per2 bits */ /* 31-0 reserved and must be 0 */ /* * TPM_FAMILY_FLAGS ([TPM_Part2], Section 20.3) * These flags indicate the operational state of the delegation and * family table. These flags are additions to TPM_PERMANENT_FLAGS and * are not standalone values. */ /* 31-2 reserved and must be 0 */ #define TPM_DELEGATE_ADMIN_LOCK (1 << 1) #define TPM_FAMFLAG_ENABLED (1 << 0) /* * TPM_FAMILY_LABEL ([TPM_Part2], Section 20.4) * Used in the family table to hold a one-byte numeric value (sequence number) * that software can map to a string of bytes. */ typedef struct tdTPM_FAMILY_LABEL { BYTE label; } TPM_FAMILY_LABEL; #define sizeof_TPM_FAMILY_LABEL(s) (1) /* * TPM_FAMILY_TABLE_ENTRY ([TPM_Part2], Section 20.5) * The family table entry is an individual row in the family table. */ #define TPM_TAG_FAMILY_TABLE_ENTRY 0x0025 typedef struct tdTPM_FAMILY_TABLE_ENTRY { TPM_STRUCTURE_TAG tag; TPM_FAMILY_LABEL familyLabel; TPM_FAMILY_ID familyID; TPM_FAMILY_VERIFICATION verificationCount; TPM_FAMILY_FLAGS flags; /* only for internal use */ BOOL valid; } TPM_FAMILY_TABLE_ENTRY; #define sizeof_TPM_FAMILY_TABLE_ENTRY(s) (2 + 1 + 4 + 4 + 4) /* * TPM_FAMILY_TABLE ([TPM_Part2], Section 20.6) * The family table is stored in a TPM shielded location. There are no * confidential values in the family table. The family table contains * a minimum of 8 rows. */ #define TPM_NUM_FAMILY_TABLE_ENTRY 16 typedef struct tdTPM_FAMILY_TABLE { TPM_FAMILY_TABLE_ENTRY famRow[TPM_NUM_FAMILY_TABLE_ENTRY]; } TPM_FAMILY_TABLE; /* * TPM_DELEGATE_LABEL ([TPM_Part2], Section 20.7) * Used in the delegate table to hold a byte that can be displayed or * used by applications. */ typedef struct tdTPM_DELEGATE_LABEL { BYTE label; } TPM_DELEGATE_LABEL; #define sizeof_TPM_DELEGATE_LABEL(s) (1) /* * TPM_DELEGATE_PUBLIC ([TPM_Part2], Section 20.8) * The information of a delegate row that is public and does not have any * sensitive information. */ #define TPM_TAG_DELEGATE_PUBLIC 0x001B typedef struct tdTPM_DELEGATE_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_LABEL rowLabel; TPM_PCR_INFO_SHORT pcrInfo; TPM_DELEGATIONS permissions; TPM_FAMILY_ID familyID; TPM_FAMILY_VERIFICATION verificationCount; } TPM_DELEGATE_PUBLIC; #define sizeof_TPM_DELEGATE_PUBLIC(s) (2 + 1 \ + sizeof_TPM_PCR_INFO_SHORT(s.pcrInfo) \ + sizeof_TPM_DELEGATIONS(s.permissions) + 4 + 4) /* * TPM_DELEGATE_TABLE_ROW ([TPM_Part2], Section 20.9) * A row of the delegate table. */ #define TPM_TAG_DELEGATE_TABLE_ROW 0x001C typedef struct tdTPM_DELEGATE_TABLE_ROW { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_PUBLIC pub; TPM_SECRET authValue; /* only for internal use */ BOOL valid; } TPM_DELEGATE_TABLE_ROW; #define sizeof_TPM_DELEGATE_TABLE_ROW(s) (2 \ + sizeof_TPM_DELEGATE_PUBLIC(s.pub) + 20) /* * TPM_DELEGATE_TABLE ([TPM_Part2], Section 20.10) * This is the delegate table. The table contains a minimum of 2 rows. * This will be an entry in the TPM_PERSISTENT_DATA structure. */ #define TPM_NUM_DELEGATE_TABLE_ENTRY 4 typedef struct tdTPM_DELEGATE_TABLE { TPM_DELEGATE_TABLE_ROW delRow[TPM_NUM_DELEGATE_TABLE_ENTRY]; } TPM_DELEGATE_TABLE; /* * TPM_DELEGATE_SENSITIVE ([TPM_Part2], Section 20.11) * The TPM_DELEGATE_SENSITIVE structure is the area of a delegate * blob that contains sensitive information. */ #define TPM_TAG_DELEGATE_SENSITIVE 0x0026 typedef struct tdTPM_DELEGATE_SENSITIVE { TPM_STRUCTURE_TAG tag; TPM_SECRET authValue; } TPM_DELEGATE_SENSITIVE; #define sizeof_TPM_DELEGATE_SENSITIVE(s) (2 + 20) /* * TPM_DELEGATE_OWNER_BLOB ([TPM_Part2], Section 20.12) * This data structure contains all the information necessary to * externally store a set of owner delegation rights. */ #define TPM_TAG_DELEGATE_OWNER_BLOB 0x002A typedef struct tdTPM_DELEGATE_OWNER_BLOB { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_PUBLIC pub; TPM_DIGEST integrityDigest; UINT32 additionalSize; BYTE* additionalArea; UINT32 sensitiveSize; BYTE* sensitiveArea; } TPM_DELEGATE_OWNER_BLOB; #define sizeof_TPM_DELEGATE_OWNER_BLOB(s) (2 \ + sizeof_TPM_DELEGATE_PUBLIC(s.pub) + 20 \ + 4 + s.additionalSize + 4 + s.sensitiveSize) #define free_TPM_DELEGATE_OWNER_BLOB(s) { \ if (s.additionalSize > 0) tpm_free(s.additionalArea); \ if (s.sensitiveSize > 0) tpm_free(s.sensitiveArea); } /* * TPM_DELEGATE_KEY_BLOB ([TPM_Part2], Section 20.13) * A structure identical to TPM_DELEGATE_OWNER_BLOB but which stores * delegation information for user keys. */ #define TPM_TAG_DELEGATE_KEY_BLOB 0x0027 typedef struct tdTPM_DELEGATE_KEY_BLOB { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_PUBLIC pub; TPM_DIGEST integrityDigest; TPM_DIGEST pubKeyDigest; UINT32 additionalSize; BYTE* additionalArea; UINT32 sensitiveSize; BYTE* sensitiveArea; } TPM_DELEGATE_KEY_BLOB; #define sizeof_TPM_DELEGATE_KEY_BLOB(s) (2 \ + sizeof_TPM_DELEGATE_PUBLIC(s.pub) + 20 + 20 \ + 4 + s.additionalSize + 4 + s.sensitiveSize) #define free_TPM_DELEGATE_KEY_BLOB(s) { \ if (s.additionalSize > 0) tpm_free(s.additionalArea); \ if (s.sensitiveSize > 0) tpm_free(s.sensitiveArea); } /* * TPM_FAMILY_OPERATION Values ([TPM_Part2], Section 20.14) * These are the opFlag values used by TPM_Delegate_Manage. */ #define TPM_FAMILY_CREATE 0x00000001 #define TPM_FAMILY_ENABLE 0x00000002 #define TPM_FAMILY_ADMIN 0x00000003 #define TPM_FAMILY_INVALIDATE 0x00000004 /* * TPM_CAPABILITY_AREA Values for TPM_GetCapability ([TPM_Part2], Section 21.1) */ #define TPM_CAP_ORD 0x00000001 #define TPM_CAP_ALG 0x00000002 #define TPM_CAP_PID 0x00000003 #define TPM_CAP_FLAG 0x00000004 #define TPM_CAP_PROPERTY 0x00000005 #define TPM_CAP_VERSION 0x00000006 #define TPM_CAP_KEY_HANDLE 0x00000007 #define TPM_CAP_CHECK_LOADED 0x00000008 #define TPM_CAP_SYM_MODE 0x00000009 #define TPM_CAP_KEY_STATUS 0x0000000C #define TPM_CAP_NV_LIST 0x0000000D #define TPM_CAP_MFR 0x00000010 #define TPM_CAP_NV_INDEX 0x00000011 #define TPM_CAP_TRANS_ALG 0x00000012 #define TPM_CAP_HANDLE 0x00000014 #define TPM_CAP_TRANS_ES 0x00000015 #define TPM_CAP_AUTH_ENCRYPT 0x00000017 #define TPM_CAP_SELECT_SIZE 0x00000018 #define TPM_CAP_DA_LOGIC 0x00000019 #define TPM_CAP_VERSION_VAL 0x0000001A /* subCap definitions ([TPM_Part2], Section 21.2) */ #define TPM_CAP_PROP_PCR 0x00000101 #define TPM_CAP_PROP_DIR 0x00000102 #define TPM_CAP_PROP_MANUFACTURER 0x00000103 #define TPM_CAP_PROP_KEYS 0x00000104 #define TPM_CAP_PROP_MIN_COUNTER 0x00000107 #define TPM_CAP_FLAG_PERMANENT 0x00000108 #define TPM_CAP_FLAG_VOLATILE 0x00000109 #define TPM_CAP_PROP_AUTHSESS 0x0000010A #define TPM_CAP_PROP_TRANSESS 0x0000010B #define TPM_CAP_PROP_COUNTERS 0x0000010C #define TPM_CAP_PROP_MAX_AUTHSESS 0x0000010D #define TPM_CAP_PROP_MAX_TRANSESS 0x0000010E #define TPM_CAP_PROP_MAX_COUNTERS 0x0000010F #define TPM_CAP_PROP_MAX_KEYS 0x00000110 #define TPM_CAP_PROP_OWNER 0x00000111 #define TPM_CAP_PROP_CONTEXT 0x00000112 #define TPM_CAP_PROP_MAX_CONTEXT 0x00000113 #define TPM_CAP_PROP_FAMILYROWS 0x00000114 #define TPM_CAP_PROP_TIS_TIMEOUT 0x00000115 #define TPM_CAP_PROP_STARTUP_EFFECT 0x00000116 #define TPM_CAP_PROP_DELEGATE_ROW 0x00000117 #define TPM_CAP_PROP_MAX_DAASESS 0x00000119 #define TPM_CAP_PROP_DAASESS 0x0000011A #define TPM_CAP_PROP_CONTEXT_DIST 0x0000011B #define TPM_CAP_PROP_DAA_INTERRUPT 0x0000011C #define TPM_CAP_PROP_SESSIONS 0x0000011D #define TPM_CAP_PROP_MAX_SESSIONS 0x0000011E #define TPM_CAP_PROP_CMK_RESTRICTION 0x0000011F #define TPM_CAP_PROP_DURATION 0x00000120 #define TPM_CAP_PROP_ACTIVE_COUNTER 0x00000122 #define TPM_CAP_PROP_MAX_NV_AVAILABLE 0x00000123 #define TPM_CAP_PROP_INPUT_BUFFER 0x00000124 /* * TPM_CAPABILITY_AREA Values for TPM_SetCapability ([TPM_Part2], Section 21.4) */ #define TPM_SET_PERM_FLAGS 0x00000001 #define TPM_SET_PERM_DATA 0x00000002 #define TPM_SET_STCLEAR_FLAGS 0x00000003 #define TPM_SET_STCLEAR_DATA 0x00000004 #define TPM_SET_STANY_FLAGS 0x00000005 #define TPM_SET_STANY_DATA 0x00000006 #define TPM_SET_VENDOR 0x00000007 /* * TPM_CAP_VERSION_INFO ([TPM_Part2], Section 21.6) * This structure is an output from a TPM_GetCapability request. * The TPM returns the current version and revision of the TPM. */ #define TPM_TAG_CAP_VERSION_INFO 0x0030 typedef struct tdTPM_CAP_VERSION_INFO { TPM_STRUCTURE_TAG tag; TPM_VERSION version; UINT16 specLevel; BYTE errataRev; BYTE tpmVendorID[4]; UINT16 vendorSpecificSize; BYTE* vendorSpecific; } TPM_CAP_VERSION_INFO; #define sizeof_TPM_CAP_VERSION_INFO(s) (sizeof(TPM_STRUCTURE_TAG) \ + sizeof(TPM_VERSION) + sizeof(UINT16) + sizeof(BYTE) + 4*sizeof(BYTE) \ + sizeof(UINT16) + s.vendorSpecificSize) /* TPM_DA_ACTION_TYPE ([TPM_Part2], Section 21.10) * This structure indicates the action taken when the dictionary attack * mitigation logic is active, when TPM_DA_STATE is TPM_DA_STATE_ACTIVE. */ #define TPM_TAG_DA_ACTION_TYPE 0x0039 typedef struct tdTPM_DA_ACTION_TYPE { TPM_STRUCTURE_TAG tag; UINT32 actions; } TPM_DA_ACTION_TYPE; #define TPM_DA_ACTION_FAILURE_MODE (1 << 3) #define TPM_DA_ACTION_DEACTIVATE (1 << 2) #define TPM_DA_ACTION_DISABLE (1 << 1) #define TPM_DA_ACTION_TIMEOUT (1 << 0) /* * TPM_DA_INFO ([TPM_Part2], Section 21.7) * This structure is an output from a TPM_GetCapability->TPM_CAP_DA_LOGIC * request if TPM_PERMANENT_FLAGS->disableFullDALogicInfo is FALSE. */ #define TPM_TAG_DA_INFO 0x0037 typedef struct tdTPM_DA_INFO { TPM_STRUCTURE_TAG tag; TPM_DA_STATE state; UINT16 currentCount; UINT16 thresholdCount; TPM_DA_ACTION_TYPE actionAtThreshold; UINT32 actionDependValue; UINT32 vendorDataSize; BYTE* vendorData; } TPM_DA_INFO; #define sizeof_TPM_DA_INFO(s) (sizeof(TPM_STRUCTURE_TAG) \ + sizeof(TPM_DA_STATE) + 2*sizeof(UINT16) + sizeof(TPM_DA_ACTION_TYPE) \ + 2*sizeof(UINT32) + s.vendorDataSize) /* * TPM_DA_INFO_LIMITED ([TPM_Part2], Section 21.8) * This structure is an output from a TPM_GetCapability->TPM_CAP_DA_LOGIC * request if TPM_PERMANENT_FLAGS->disableFullDALogicInfo is TRUE. */ #define TPM_TAG_DA_INFO_LIMITED 0x0038 typedef struct tdTPM_DA_INFO_LIMITED { TPM_STRUCTURE_TAG tag; TPM_DA_STATE state; TPM_DA_ACTION_TYPE actionAtThreshold; UINT32 vendorDataSize; BYTE* vendorData; } TPM_DA_INFO_LIMITED; #define sizeof_TPM_DA_INFO_LIMITED(s) (sizeof(TPM_STRUCTURE_TAG) \ + sizeof(TPM_DA_STATE) + sizeof(TPM_DA_ACTION_TYPE) \ + sizeof(UINT32) + s.vendorDataSize) /* * TPM_DA_STATE ([TPM_Part2], Section 21.9) * TPM_DA_STATE enumerates the possible states of the dictionary attack * mitigation logic. */ #define TPM_DA_STATE_INACTIVE 0x00 #define TPM_DA_STATE_ACTIVE 0x01 /* * DAA Structures ([TPM_Part2], Section 22) */ /* * Size and constant definitions ([TPM_Part2], Section 22.1 and 22.2) */ #define DAA_SIZE_r0 43 #define DAA_SIZE_r1 43 #define DAA_SIZE_r2 128 #define DAA_SIZE_r3 168 #define DAA_SIZE_r4 219 #define DAA_SIZE_NT 20 #define DAA_SIZE_v0 128 #define DAA_SIZE_v1 192 #define DAA_SIZE_NE 256 #define DAA_SIZE_w 256 #define DAA_SIZE_issuerModulus 256 #define DAA_power0 104 #define DAA_power1 1024 /* * TPM_DAA_ISSUER ([TPM_Part2], Section 22.3) * This structure is the abstract representation of non-secret * settings controlling a DAA context. */ #define TPM_TAG_DAA_ISSUER 0x002F typedef struct tdTPM_DAA_ISSUER { TPM_STRUCTURE_TAG tag; TPM_DIGEST DAA_digest_R0; TPM_DIGEST DAA_digest_R1; TPM_DIGEST DAA_digest_S0; TPM_DIGEST DAA_digest_S1; TPM_DIGEST DAA_digest_n; TPM_DIGEST DAA_digest_gamma; BYTE DAA_generic_q[26]; } TPM_DAA_ISSUER; #define sizeof_TPM_DAA_ISSUER(s) (2 + (6 * 20) + 26) /* * TPM_DAA_TPM ([TPM_Part2], Section 22.4) * This structure is the abstract representation of TPM specific * parameters used during a DAA context. */ #define TPM_TAG_DAA_TPM 0x0032 typedef struct tdTPM_DAA_TPM { TPM_STRUCTURE_TAG tag; TPM_DIGEST DAA_digestIssuer; TPM_DIGEST DAA_digest_v0; TPM_DIGEST DAA_digest_v1; TPM_DIGEST DAA_rekey; UINT32 DAA_count; } TPM_DAA_TPM; #define sizeof_TPM_DAA_TPM(s) (2 + (4 * 20) + 4) /* * TPM_DAA_CONTEXT ([TPM_Part2], Section 22.5) * This structure is created and used inside a TPM, and never leaves it. */ #define TPM_TAG_DAA_CONTEXT 0x002D typedef struct tdTPM_DAA_CONTEXT { TPM_STRUCTURE_TAG tag; TPM_DIGEST DAA_digestContext; TPM_DIGEST DAA_digest; TPM_DAA_CONTEXT_SEED DAA_contextSeed; BYTE DAA_scratch[256]; BYTE DAA_stage; } TPM_DAA_CONTEXT; #define sizeof_TPM_DAA_CONTEXT(s) (2 + (3 * 20) + 256 + 1) /* * TPM_DAA_JOINDATA ([TPM_Part2], Section 22.6) * This structure is the abstract representation of data that * exists only during a specific JOIN session. */ typedef struct tdTPM_DAA_JOINDATA { BYTE DAA_join_u0[128]; BYTE DAA_join_u1[138]; TPM_DIGEST DAA_digest_n0; } TPM_DAA_JOINDATA; #define sizeof_TPM_DAA_JOINDATA(s) (128 + 138 + 20) /* * TPM_DAA_BLOB ([TPM_Part2], Section 22.8) * The structure passed during the join process. */ #define TPM_TAG_DAA_BLOB 0x002C typedef struct tdTPM_DAA_BLOB { TPM_STRUCTURE_TAG tag; TPM_RESOURCE_TYPE resourceType; BYTE label[16]; TPM_DIGEST blobIntegrity; UINT32 additionalSize; BYTE* additionalData; UINT32 sensitiveSize; BYTE* sensitiveData; } TPM_DAA_BLOB; #define sizeof_TPM_DAA_BLOB(s) (sizeof(TPM_STRUCTURE_TAG) \ + sizeof(TPM_RESOURCE_TYPE) + sizeof(s.label) + sizeof(TPM_DIGEST) \ + 2*sizeof(UINT32) + s.additionalSize + s.sensitiveSize) /* * TPM_DAA_SENSITIVE ([TPM_Part2], Section 22.9) * The encrypted area for the DAA parameters. */ #define TPM_TAG_DAA_SENSITIVE 0x0031 typedef struct tdTPM_DAA_SENSITIVE { TPM_STRUCTURE_TAG tag; UINT32 internalSize; BYTE* internalData; } TPM_DAA_SENSITIVE; #define sizeof_TPM_DAA_SENSITIVE(s) (sizeof(TPM_STRUCTURE_TAG) \ + sizeof(UINT32) + s.internalSize) /* * Redirection ([TPM_Part2], Section 23) */ /* * TPM_REDIR_COMMAND ([TPM_Part2], Section 23.1) * The types of redirections. */ typedef UINT32 TPM_REDIR_COMMAND; /* * Internal Data Held By TPM ([TPM_Part2], Section 7) */ /* * TPM_PERMANENT_FLAGS ([TPM_Part2], Section 7.1) * These flags maintain state information for the TPM. The values are not * affected by any TPM_Startup command. */ #define TPM_TAG_PERMANENT_FLAGS 0x001F typedef struct tdTPM_PERMANENT_FLAGS { TPM_STRUCTURE_TAG tag; BOOL disable; BOOL ownership; BOOL deactivated; BOOL readPubek; BOOL disableOwnerClear; BOOL allowMaintenance; BOOL physicalPresenceLifetimeLock; BOOL physicalPresenceHWEnable; BOOL physicalPresenceCMDEnable; BOOL CEKPUsed; BOOL TPMpost; BOOL TPMpostLock; BOOL FIPS; BOOL operator; BOOL enableRevokeEK; BOOL nvLocked; BOOL readSRKPub; BOOL tpmEstablished; BOOL maintenanceDone; BOOL disableFullDALogicInfo; /* additional, not marshalled flags */ BOOL selfTestSucceeded; BOOL owned; BOOL dataRestored; } TPM_PERMANENT_FLAGS; #define sizeof_TPM_PERMANENT_FLAGS(s) (2 + 20) /* * TPM_STCLEAR_FLAGS ([TPM_Part2], Section 7.2) * These flags maintain state that is reset on each TPM_Startup(ST_Clear) * command. The values are not affected by TPM_Startup(ST_State) commands. */ #define TPM_TAG_STCLEAR_FLAGS 0x0020 typedef struct tdTPM_STCLEAR_FLAGS { TPM_STRUCTURE_TAG tag; BOOL deactivated; BOOL disableForceClear; BOOL physicalPresence; BOOL physicalPresenceLock; BOOL bGlobalLock; } TPM_STCLEAR_FLAGS; #define sizeof_TPM_STCLEAR_FLAGS(s) (2 + 5) /* * TPM_STANY_FLAGS ([TPM_Part2], Section 7.3) * These flags reset on any TPM_Startup command. */ #define TPM_TAG_STANY_FLAGS 0x0021 typedef struct tdTPM_STANY_FLAGS { TPM_STRUCTURE_TAG tag; BOOL postInitialise; TPM_MODIFIER_INDICATOR localityModifier; BOOL transportExclusive; BOOL TOSPresent; } TPM_STANY_FLAGS; #define sizeof_TPM_STANY_FLAGS(s) (2 + 1 + 4 + 1 + 1) /* * TPM_KEY_DATA * This structure contains the data for stored RSA keys. */ typedef struct tdTPM_KEY_DATA { TPM_PAYLOAD_TYPE payload; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_KEY_CONTROL keyControl; TPM_AUTH_DATA_USAGE authDataUsage; TPM_ENC_SCHEME encScheme; TPM_SIG_SCHEME sigScheme; TPM_SECRET usageAuth; TPM_SECRET migrationAuth; TPM_PCR_INFO pcrInfo; BOOL parentPCRStatus; tpm_rsa_private_key_t key; } TPM_KEY_DATA; #define sizeof_RSA(s) (6 + tpm_rsa_modulus_length(&s) \ + tpm_rsa_exponent_length(&s) + tpm_rsa_prime1_length(&s)) #define sizeof_TPM_KEY_DATA(s) (1 + 2 + 4 + 4 + 1 + 2 + 2 + 20 + 20 \ + ((s.keyFlags & TPM_KEY_FLAG_HAS_PCR) ? sizeof_TPM_PCR_INFO(s.pcrInfo) : 0) \ + 1 + sizeof_RSA(s.key)) #define free_TPM_KEY_DATA(s) { tpm_rsa_release_private_key(&s.key); } /* * TPM_PUBKEY_DATA * This structure contains the data for stored RSA public keys. */ typedef struct tdTPM_PUBKEY_DATA { BOOL valid; TPM_ENC_SCHEME encScheme; TPM_SIG_SCHEME sigScheme; tpm_rsa_public_key_t key; } TPM_PUBKEY_DATA; #define sizeof_RSAPub(s) (4 + tpm_rsa_public_modulus_length(&s) \ + tpm_rsa_public_exponent_length(&s)) #define sizeof_TPM_PUBKEY_DATA(s) (1 + 2 + 2 + sizeof_RSAPub(s.key)) #define free_TPM_PUBKEY_DATA(s) { tpm_rsa_release_public_key(&s.key); } /* * TPM_PERMANENT_DATA ([TPM_Part2], Section 7.4) * This structure contains the data fields that are permanently held in * the TPM and not affected by TPM_Startup(any). * * This is an informative structure and not normative. */ #define TPM_TAG_PERMANENT_DATA 0x0022 #define TPM_MAX_COUNTERS 4 #define TPM_DELEGATE_KEY TPM_KEY #define TPM_MAX_NV_WRITE_NOOWNER 64 #define TPM_MAX_KEYS 10 #define TPM_SYM_KEY_SIZE 32 #define TPM_MAX_NV_BUF_SIZE 1024 #define TPM_MAX_NVS 20 #define TPM_NUM_TIS_TIMEOUTS 4 #define TPM_NUM_CMD_DURATIONS 3 typedef struct tdTPM_PERMANENT_DATA { TPM_STRUCTURE_TAG tag; TPM_VERSION version; TPM_NONCE tpmProof; TPM_NONCE ekReset; TPM_SECRET ownerAuth; TPM_SECRET operatorAuth; TPM_DAA_TPM_SEED tpmDAASeed; TPM_NONCE daaProof; TPM_PUBKEY_DATA manuMaintPub; tpm_rsa_private_key_t endorsementKey; TPM_KEY_DATA srk; BYTE contextKey[TPM_SYM_KEY_SIZE]; BYTE delegateKey[TPM_SYM_KEY_SIZE]; BYTE daaKey[TPM_SYM_KEY_SIZE]; TPM_ACTUAL_COUNT auditMonotonicCounter; TPM_COUNTER_VALUE counters[TPM_MAX_COUNTERS]; TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; TPM_PCRVALUE pcrValue[TPM_NUM_PCR]; BYTE ordinalAuditStatus[TPM_ORD_MAX / 8]; BYTE rngState[16]; TPM_FAMILY_TABLE familyTable; TPM_DELEGATE_TABLE delegateTable; UINT32 lastFamilyID; TPM_CMK_DELEGATE restrictDelegate; UINT32 maxNVBufSize; UINT32 noOwnerNVWrite; UINT32 nvDataSize; BYTE nvData[TPM_MAX_NV_SIZE]; TPM_NV_DATA_SENSITIVE nvStorage[TPM_MAX_NVS]; TPM_KEY_DATA keys[TPM_MAX_KEYS]; UINT32 tis_timeouts[TPM_NUM_TIS_TIMEOUTS]; UINT32 cmd_durations[TPM_NUM_CMD_DURATIONS]; const char *testResult; } TPM_PERMANENT_DATA; static inline int sizeof_TPM_PERMANENT_DATA(TPM_PERMANENT_DATA *s) { int i, size = 2 + 4 + 6*20; size += (s->manuMaintPub.valid) ? sizeof_TPM_PUBKEY_DATA((s->manuMaintPub)) : 1; size += sizeof_RSA(s->endorsementKey); size += (s->srk.payload != TPM_PT_NONE) ? sizeof_TPM_KEY_DATA(s->srk) : 1; size += 3*TPM_SYM_KEY_SIZE + 4; for (i = 0; i < TPM_MAX_COUNTERS; i++) { size += sizeof_TPM_COUNTER_VALUE2((s->counters[i])); } size += TPM_NUM_PCR*(sizeof_TPM_PCR_ATTRIBUTES(x) + 20) + TPM_ORD_MAX/8 + 16; for (i = 0; i < TPM_NUM_FAMILY_TABLE_ENTRY; i++) { size += 1; if (s->familyTable.famRow[i].valid) size += sizeof_TPM_FAMILY_TABLE_ENTRY((s->familyTable.famRow[i])); } for (i = 0; i < TPM_NUM_DELEGATE_TABLE_ENTRY; i++) { size += 1; if (s->delegateTable.delRow[i].valid) size += sizeof_TPM_DELEGATE_TABLE_ROW((s->delegateTable.delRow[i])); } size += 5*4 + TPM_MAX_NV_SIZE; for (i = 0; i < TPM_MAX_NVS; i++) { size += 1; if (s->nvStorage[i].valid) size += sizeof_TPM_NV_DATA_SENSITIVE((s->nvStorage[i])); } for (i = 0; i < TPM_MAX_KEYS; i++) { if (s->keys[i].payload != TPM_PT_NONE) size += sizeof_TPM_KEY_DATA((s->keys[i])); else size += 1; } size += TPM_NUM_TIS_TIMEOUTS * 4; size += TPM_NUM_CMD_DURATIONS * 4; return size; } static inline void free_TPM_PERMANENT_DATA(TPM_PERMANENT_DATA *s) { int i; /* release the EK, SRK as well as all other rsa keys */ if (s->endorsementKey.size > 0) tpm_rsa_release_private_key(&s->endorsementKey); if (s->srk.payload) free_TPM_KEY_DATA(s->srk); if (s->manuMaintPub.valid) free_TPM_PUBKEY_DATA(s->manuMaintPub); for (i = 0; i < TPM_MAX_KEYS; i++) if (s->keys[i].payload) free_TPM_KEY_DATA(s->keys[i]); } /* * TPM_STCLEAR_DATA ([TPM_Part2], Section 7.5) * Most of the data in this structure resets on TPM_Startup(ST_Clear). * * This is an informative structure and not normative. */ #define TPM_TAG_STCLEAR_DATA 0x0023 typedef struct tdTPM_STCLEAR_DATA { TPM_STRUCTURE_TAG tag; TPM_NONCE contextNonceKey; TPM_COUNT_ID countID; UINT32 ownerReference; BOOL disableResetLock; UINT32 deferredPhysicalPresence; } TPM_STCLEAR_DATA; #define sizeof_TPM_STCLEAR_DATA(s) (2 + 20 + 4 + 4 + 1 + 4) /* * TPM_SESSION_DATA * This structure contains the data for authorization and transport sessions. */ #define TPM_ST_INVALID 0 #define TPM_ST_OIAP 1 #define TPM_ST_OSAP 2 #define TPM_ST_TRANSPORT 4 #define TPM_ST_DAA 8 #define TPM_ST_DSAP 16 typedef struct tdTPM_SESSION_DATA { BYTE type; TPM_NONCE nonceEven; TPM_NONCE lastNonceEven; TPM_SECRET sharedSecret; TPM_HANDLE handle; TPM_ENTITY_TYPE entityType; TPM_DELEGATIONS permissions; TPM_FAMILY_ID familyID; TPM_TRANSPORT_INTERNAL transInternal; } TPM_SESSION_DATA; #define sizeof_TPM_SESSION_DATA(s) (1 + 3*20 + 4 + 2 \ + ((s.type == TPM_ST_DSAP) ? \ sizeof_TPM_DELEGATIONS(s.delegations) + 4 : 0) \ + ((s.type == TPM_ST_TRANSPORT) ? \ sizeof_TPM_TRANSPORT_INTERNAL(s.transInternal) : 0)) /* * TPM_DAA_SESSION_DATA * This structure contains the data for DAA sessions. */ typedef UINT32 TPM_DAAHANDLE; typedef struct tdTPM_DAA_SESSION_DATA { BYTE type; TPM_DAA_ISSUER DAA_issuerSettings; TPM_DAA_TPM DAA_tpmSpecific; TPM_DAA_CONTEXT DAA_session; TPM_DAA_JOINDATA DAA_joinSession; TPM_HANDLE handle; } TPM_DAA_SESSION_DATA; #define sizeof_TPM_DAA_SESSION_DATA(s) (1 \ + sizeof_TPM_DAA_ISSUER(s.DAA_issuerSettings) \ + sizeof_TPM_DAA_TPM(s.DAA_tpmSpecific) \ + sizeof_TPM_DAA_CONTEXT(s.DAA_session) \ + sizeof_TPM_DAA_JOINDATA(s.DAA_joinSession) + 4) /* * TPM_STANY_DATA ([TPM_Part2], Section 7.6) * Most of the data in this structure resets on TPM_Startup(ST_State). * * This is an informative structure and not normative. */ #define TPM_TAG_STANY_DATA 0x0024 #define TPM_MAX_SESSIONS 4 #define TPM_MAX_SESSION_LIST 16 #define TPM_MAX_SESSIONS_DAA 1 typedef struct tdTPM_STANY_DATA { TPM_STRUCTURE_TAG tag; TPM_NONCE contextNonceSession; TPM_DIGEST auditDigest; BOOL auditSession; TPM_CURRENT_TICKS currentTicks; UINT32 contextCount; UINT32 contextList[TPM_MAX_SESSION_LIST]; TPM_SESSION_DATA sessions[TPM_MAX_SESSIONS]; TPM_DAA_SESSION_DATA sessionsDAA[TPM_MAX_SESSIONS_DAA]; TPM_DAAHANDLE currentDAA; TPM_TRANSHANDLE transExclusive; } TPM_STANY_DATA; #define sizeof_TPM_STANY_DATA(s) (2 + 20 + 20 + 1 \ + sizeof_TPM_CURRENT_TICKS(s.currentTicks) \ + 4 + (4 * TPM_MAX_SESSION_LIST) \ + (sizeof_TPM_SESSION_DATA(s.sessions[0]) * TPM_MAX_SESSIONS) \ + (sizeof_TPM_DAA_SESSION_DATA(s.sessionsDAA[0]) * TPM_MAX_SESSIONS_DAA) \ + 4 + 4) /* * TPM_DATA * Internal data of the TPM */ typedef struct tdTPM_DATA { struct { TPM_PERMANENT_FLAGS flags; TPM_PERMANENT_DATA data; } permanent; struct { TPM_STCLEAR_FLAGS flags; TPM_STCLEAR_DATA data; } stclear; struct { TPM_STANY_FLAGS flags; TPM_STANY_DATA data; } stany; } TPM_DATA; #define sizeof_TPM_DATA(s) ( \ sizeof_TPM_PERMANENT_FLAGS(s.permanent.flags) + 2 \ + sizeof_TPM_PERMANENT_DATA(&s.permanent.data) \ + sizeof_TPM_STCLEAR_FLAGS(s.stclear.flags) \ + sizeof_TPM_STCLEAR_DATA(s.stclear.data) \ + sizeof_TPM_STANY_DATA(s.stany.data)) #define free_TPM_DATA(s) { free_TPM_PERMANENT_DATA(&s.permanent.data); } /* * Context Structures */ /* * TPM_CONTEXT_BLOB ([TPM_Part2], Section 18.1) * This is the header for the wrapped context. The blob contains all * information necessary to reload the context back into the TPM. */ #define TPM_TAG_CONTEXTBLOB 0x0001 typedef struct tdTPM_CONTEXT_BLOB { TPM_STRUCTURE_TAG tag; TPM_RESOURCE_TYPE resourceType; TPM_HANDLE handle; BYTE label[16]; UINT32 contextCount; TPM_DIGEST integrityDigest; UINT32 additionalSize; BYTE* additionalData; UINT32 sensitiveSize; BYTE* sensitiveData; } TPM_CONTEXT_BLOB; #define sizeof_TPM_CONTEXT_BLOB(s) (2 + 4 + 4 + 16 + 4 + 20 \ + 4 + s.additionalSize + 4 + s.sensitiveSize) #define free_TPM_CONTEXT_BLOB(s) { \ if (s.additionalSize > 0) tpm_free(s.additionalData); \ if (s.sensitiveSize > 0) tpm_free(s.sensitiveData); } /* * TPM_CONTEXT_SENSITIVE ([TPM_Part2], Section 18.2) * The internal areas that the TPM needs to encrypt and store off the TPM. * This is an informative structure and the TPM can implement in any * manner they wish. */ #define TPM_TAG_CONTEXT_SENSITIVE 0x0002 typedef struct tdTPM_CONTEXT_SENSITIVE { TPM_STRUCTURE_TAG tag; TPM_NONCE contextNonce; UINT32 internalSize; TPM_RESOURCE_TYPE resourceType; union { TPM_KEY_DATA key; TPM_SESSION_DATA session; TPM_DAA_SESSION_DATA sessionDAA; } internalData; } TPM_CONTEXT_SENSITIVE; #define sizeof_TPM_CONTEXT_SENSITIVE(s) (2 + 20 + 4 + 4 + s.internalSize) /* * TPM communication packets */ /* * TPM_REQUEST * TPM command request */ typedef struct tdTPM_REQUEST { TPM_TAG tag; UINT32 size; TPM_COMMAND_CODE ordinal; BYTE *param; UINT32 paramSize; TPM_AUTH auth1; TPM_AUTH auth2; } TPM_REQUEST; /* * TPM_RESPONSE * TPM command response */ typedef struct tdTPM_RESPONSE { TPM_TAG tag; UINT32 size; TPM_RESULT result; BYTE *param; UINT32 paramSize; TPM_AUTH *auth1; TPM_AUTH *auth2; } TPM_RESPONSE; #endif /* _TPM_STRUCTURES_H_ */ ================================================ FILE: tpm/tpm_testing.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_testing.c 364 2010-02-11 10:24:45Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "crypto/sha1.h" #include "crypto/hmac.h" #include "crypto/rsa.h" #define INTERVAL(x,a,b) ((a) <= (x) && (x) <= (b)) static int tpm_test_prng(void) { int ones[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; int run_len0 = 0; int run_len1 = 0; int monobit = 0; int poker[16] = {0}; int run0[6] = {0}; int run1[6] = {0}; int run_34 = 0; unsigned long x = 0; unsigned int i, j, k; BYTE buf[25]; debug("tpm_test_prng()"); /* Statistical random number generator tests according to FIPS 140-1 */ for (i = 0; i < 2500 / sizeof(buf); i++) { tpm_get_random_bytes(buf, sizeof(buf)); for (j = 0; j < sizeof(buf); j++) { BYTE hi = (buf[j] >> 4) & 0x0f; BYTE lo = buf[j] & 0x0f; monobit += ones[hi] + ones[lo]; poker[hi]++; poker[lo]++; for (k = 0; k < 8; k++) { if ((buf[j] >> k) & 0x01) { run_len1++; if (run_len0 >= 34) run_34 = 1; if (run_len0 >= 6) run0[5]++; else if (run_len0 > 0) run0[run_len0 - 1]++; run_len0 = 0; } else { run_len0++; if (run_len1 >= 34) run_34 = 1; if (run_len1 >= 6) run1[5]++; else if (run_len1 > 0) run1[run_len1 - 1]++; run_len1 = 0; } } } } /* evaluate result */ /* x = sum(poker[i]^2) * 16 / 5000 - 5000 */ for (i = 0; i < 16; i++) x += 16 * poker[i] * poker[i] / 50; x -= 5000 * 100; debug("Monobit: %d", monobit); debug("Poker: %d.%d", (int)(x/100), (int)(x/10)%10); debug("run_1: %d, %d", run0[0], run1[0]); debug("run_2: %d, %d", run0[1], run1[1]); debug("run_3: %d, %d", run0[2], run1[2]); debug("run_4: %d, %d", run0[3], run1[3]); debug("run_5: %d, %d", run0[4], run1[4]); debug("run_6+: %d, %d", run0[5], run1[5]); debug("run_34: %d", run_34); if (INTERVAL(monobit, 9654, 10346) && INTERVAL(x, 103, 5740) && INTERVAL(run0[0], 2267, 2733) && INTERVAL(run1[0], 2267, 2733) && INTERVAL(run0[1], 1079, 1421) && INTERVAL(run1[1], 1079, 1421) && INTERVAL(run0[2], 502, 748) && INTERVAL(run1[2], 502, 748) && INTERVAL(run0[3], 223, 402) && INTERVAL(run1[3], 223, 402) && INTERVAL(run0[4], 90, 223) && INTERVAL(run1[4], 90, 223) && INTERVAL(run0[5], 90, 223) && INTERVAL(run1[5], 90, 223) && !run_34) return 0; return -1; } static int tpm_test_sha1(void) { tpm_sha1_ctx_t ctx; BYTE digest[SHA1_DIGEST_LENGTH]; unsigned int i, j; /* test cases for SHA-1 given in FIPS PUB 180-1 */ struct { const char *data; uint32_t repetitions; const char *digest; } test_cases[] = {{ "abc", 1, "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D" }, { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1" }, { "a", 1000000, "\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" }, { "0123456701234567012345670123456701234567012345670123456701234567", 10, "\xDE\xA3\x56\xA2\xCD\xDD\x90\xC7\xA7\xEC\xED\xC5\xEB\xB5\x63\x93\x4F\x46\x04\x52" }}; debug("tpm_test_sha1()"); for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) { tpm_sha1_init(&ctx); for (j = 0; j < test_cases[i].repetitions; j++) tpm_sha1_update(&ctx, (uint8_t*)test_cases[i].data, strlen(test_cases[i].data)); tpm_sha1_final(&ctx, digest); if (memcmp(digest, test_cases[i].digest, SHA1_DIGEST_LENGTH) != 0) return -1; } return 0; } static int tpm_test_hmac(void) { tpm_hmac_ctx_t ctx; uint8_t digest[SHA1_DIGEST_LENGTH]; unsigned int i, j; /* test cases for HMAC-SHA-1 given in RFC 2202 */ struct { const char *key; uint8_t key_len; const char *data; uint8_t data_len; const char *digest; } test_cases[] = {{ "\x0b", 20, "Hi There", 8, "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00" }, { "Jefe", 4, "what do ya want for nothing?", 28, "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79" }, { "\xaa", 20, "\xdd", 50, "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3" }, { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" "\x15\x16\x17\x18\x19", 25, "\xcd", 50, "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda" }, { "\x0c", 20, "Test With Truncation", 20, "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04" }, { "\xaa", 80, "Test Using Larger Than Block-Size Key - Hash Key First", 54, "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12" }, { "\xaa", 80, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73, "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91" }}; debug("tpm_test_hmac()"); for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) { if (strlen(test_cases[i].key) < test_cases[i].key_len) { uint8_t key[test_cases[i].key_len]; memset(key, test_cases[i].key[0], test_cases[i].key_len); tpm_hmac_init(&ctx, (uint8_t*)key, test_cases[i].key_len); } else { tpm_hmac_init(&ctx, (uint8_t*)test_cases[i].key, test_cases[i].key_len); } for (j = 0; j < test_cases[i].data_len; j += strlen(test_cases[i].data)) { tpm_hmac_update(&ctx, (uint8_t *)test_cases[i].data, strlen(test_cases[i].data)); } tpm_hmac_final(&ctx, digest); if (memcmp(digest, test_cases[i].digest, SHA1_DIGEST_LENGTH) != 0) return -1; } return 0; } static int tpm_test_rsa_EK(void) { int res = 0; uint8_t *data = (uint8_t*)"RSA PKCS #1 v1.5 Test-String"; uint8_t buf[256]; size_t buf_len, data_len = strlen((char*)data); tpm_rsa_private_key_t priv_key; tpm_rsa_public_key_t pub_key; debug("tpm_test_rsa_EK()"); /* generate and test key-pair */ debug("tpm_rsa_generate_key()"); res = tpm_rsa_generate_key(&priv_key, 512); tpm_rsa_release_private_key(&priv_key); if (res) return res; /* test endorsement key */ debug("testing endorsement key"); do { priv_key = tpmData.permanent.data.endorsementKey; if (!priv_key.size) return 0; TPM_RSA_EXTRACT_PUBLIC_KEY(priv_key, pub_key); /* test sign and verify functions */ debug("tpm_rsa_sign(RSA_SSA_PKCS1_SHA1)"); res = tpm_rsa_sign(&priv_key, RSA_SSA_PKCS1_SHA1, data, data_len, buf); if (res) break; debug("tpm_rsa_verify(RSA_SSA_PKCS1_SHA1)"); res = tpm_rsa_verify(&pub_key, RSA_SSA_PKCS1_SHA1, data, data_len, buf); if (res) break; debug("tpm_rsa_sign(RSA_SSA_PKCS1_DER)"); res = tpm_rsa_sign(&priv_key, RSA_SSA_PKCS1_DER, data, data_len, buf); if (res) break; debug("tpm_rsa_verify(RSA_SSA_PKCS1_DER)"); res = tpm_rsa_verify(&pub_key, RSA_SSA_PKCS1_DER, data, data_len, buf); if (res) break; /* test encryption and decryption */ debug("tpm_rsa_encrypt(RSA_ES_PKCSV15)"); res = tpm_rsa_encrypt(&pub_key, RSA_ES_PKCSV15, data, data_len, buf, &buf_len); if (res) break; debug("tpm_rsa_decrypt(RSA_ES_PKCSV15)"); res = tpm_rsa_decrypt(&priv_key, RSA_ES_PKCSV15, buf, buf_len, buf, &buf_len); if (res) break; debug("verify plain text"); res = !((buf_len == data_len) && !memcmp(buf, data, buf_len)); if (res) break; debug("tpm_rsa_encrypt(RSA_ES_OAEP_SHA1)"); res = tpm_rsa_encrypt(&pub_key, RSA_ES_OAEP_SHA1, data, data_len/2, buf, &buf_len); if (res) break; debug("tpm_rsa_decrypt(RSA_ES_OAEP_SHA1)"); res = tpm_rsa_decrypt(&priv_key, RSA_ES_OAEP_SHA1, buf, buf_len, buf, &buf_len); if (res) break; debug("verify plain text"); res = !(buf_len == data_len/2 && !memcmp(buf, data, buf_len)); } while (0); /* release public key and exit */ tpm_rsa_release_public_key(&pub_key); return res; } /* * Admin Testing ([TPM_Part3], Section 4) */ TPM_RESULT TPM_SelfTestFull(void) { info("TPM_SelfTestFull()"); if (tpm_test_prng() != 0) { tpmData.permanent.data.testResult = "tpm_test_prng() failed"; tpmData.permanent.flags.selfTestSucceeded = FALSE; } else if (tpm_test_sha1() != 0) { tpmData.permanent.data.testResult = "tpm_test_sha1() failed"; tpmData.permanent.flags.selfTestSucceeded = FALSE; } else if (tpm_test_hmac() != 0) { tpmData.permanent.data.testResult = "tpm_test_hmac() failed"; tpmData.permanent.flags.selfTestSucceeded = FALSE; } else if (tpm_test_rsa_EK() != 0) { tpmData.permanent.data.testResult = "tpm_test_rsa_EK() failed"; tpmData.permanent.flags.selfTestSucceeded = FALSE; } else { tpmData.permanent.data.testResult = "Success"; tpmData.permanent.flags.selfTestSucceeded = TRUE; } if (tpmData.permanent.flags.selfTestSucceeded) { info("Self-Test succeeded"); } else { error("Self-Test failed: %s", tpmData.permanent.data.testResult); } return TPM_SUCCESS; } TPM_RESULT TPM_ContinueSelfTest(void) { info("TPM_ContinueSelfTest()"); /* we just run a complete self-test */ return TPM_SelfTestFull(); } TPM_RESULT TPM_GetTestResult(UINT32 *outDataSize, BYTE **outData) { info("TPM_GetTestResult()"); if (tpmData.permanent.data.testResult == NULL) return TPM_FAIL; *outDataSize = strlen(tpmData.permanent.data.testResult) + 1; *outData = tpm_malloc(*outDataSize); if (*outData == NULL) return TPM_FAIL; memcpy(*outData, tpmData.permanent.data.testResult, *outDataSize); return TPM_SUCCESS;; } ================================================ FILE: tpm/tpm_ticks.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_ticks.c 453 2010-09-11 11:00:58Z mast $ */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_data.h" #include "tpm_handles.h" #include "tpm_marshalling.h" /* * Timing Ticks ([TPM_Part3], Section 23) * The TPM timing ticks are always available for use. The association of * timing ticks to actual time is a protocol that occurs outside of the TPM. * See the design document for details. */ TPM_RESULT TPM_GetTicks(TPM_CURRENT_TICKS *currentTime) { info("TPM_GetTicks()"); memcpy(currentTime, &tpmData.stany.data.currentTicks, sizeof(TPM_CURRENT_TICKS)); return TPM_SUCCESS; } TPM_RESULT TPM_TickStampBlob(TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_DIGEST *digestToStamp, TPM_AUTH *auth1, TPM_CURRENT_TICKS *currentTicks, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; BYTE *info_buffer, *ptr; UINT32 info_length, len; info("TPM_TickStampBlob()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth1->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; } if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY && key->keyUsage != TPM_KEY_IDENTITY) return TPM_INVALID_KEYUSAGE; if (key->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) return TPM_INAPPROPRIATE_SIG; /* get current ticks */ TPM_GetTicks(currentTicks); /* sign data using signature scheme PKCS1_SHA1 and TPM_SIGN_INFO container */ *sigSize = key->key.size >> 3; *sig = tpm_malloc(*sigSize); if (*sig == NULL) return TPM_FAIL; /* setup TPM_SIGN_INFO structure */ info_length = 30 + sizeof(TPM_DIGEST) + sizeof_TPM_CURRENT_TICKS(currentTicks); info_buffer = tpm_malloc(info_length); if (info_buffer == NULL) { tpm_free(*sig); return TPM_FAIL; } memcpy(&info_buffer[0], "\x00\x05TSTP", 6); memcpy(&info_buffer[6], antiReplay->nonce, 20); ptr = &info_buffer[26]; len = info_length - 26; tpm_marshal_UINT32(&ptr, &len, info_length - 30); memcpy(ptr, digestToStamp->digest, sizeof(TPM_DIGEST)); ptr += sizeof(TPM_DIGEST); len -= sizeof(TPM_DIGEST); if (tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, currentTicks) || tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1, info_buffer, info_length, *sig)) { tpm_free(*sig); tpm_free(info_buffer); return TPM_FAIL; } return TPM_SUCCESS; } void tpm_update_ticks(void) { if (tpmData.stany.data.currentTicks.tag == 0) { tpmData.stany.data.currentTicks.tag = TPM_TAG_CURRENT_TICKS; tpmData.stany.data.currentTicks.currentTicks += tpm_get_ticks(); tpm_get_random_bytes(tpmData.stany.data.currentTicks.tickNonce.nonce, sizeof(TPM_NONCE)); tpmData.stany.data.currentTicks.tickRate = 1; } else { tpmData.stany.data.currentTicks.currentTicks += tpm_get_ticks(); } } ================================================ FILE: tpm/tpm_transport.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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_transport.c 367 2010-02-13 15:52:18Z mast $ */ /* * Thanks go to Edison Su () for providing * the initial Transport Session patch. */ #include "tpm_emulator.h" #include "tpm_commands.h" #include "tpm_handles.h" #include "tpm_marshalling.h" #include "tpm_data.h" #include "crypto/rsa.h" #include "crypto/sha1.h" /* * Transport Sessions ([TPM_Part3], Section 24) */ static void debug_buf(const char *str, uint8_t *buf, size_t buf_len) { static char map[] = "0123456789abcdef"; char hex[buf_len * 3]; size_t i; for (i = 0; i < buf_len; i++) { hex[i*3 + 0] = map[buf[i] >> 4]; hex[i*3 + 1] = map[buf[i] & 0x0f]; hex[i*3 + 2] = ' '; } hex[sizeof(hex) - 1] = 0; debug("%s%s", str, hex); } 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 void transport_log_in(BYTE *params, BYTE *pubKeyHash, TPM_DIGEST *transDigest) { BYTE *ptr, buf[sizeof_TPM_TRANSPORT_LOG_IN(x)]; UINT32 len; tpm_sha1_ctx_t sha1; ptr = buf; len = sizeof(buf); tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_TRANSPORT_LOG_IN); tpm_marshal_BLOB(&ptr, &len, params, SHA1_DIGEST_LENGTH); tpm_marshal_BLOB(&ptr, &len, pubKeyHash, SHA1_DIGEST_LENGTH); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, transDigest->digest, sizeof(transDigest->digest)); tpm_sha1_update(&sha1, buf, sizeof(buf)); tpm_sha1_final(&sha1, transDigest->digest); debug_buf("LogIn: transDigest: ", transDigest->digest, sizeof(transDigest->digest)); } static void transport_log_out(BYTE *params, TPM_DIGEST *transDigest) { BYTE *ptr, buf[sizeof_TPM_TRANSPORT_LOG_OUT(x)]; UINT32 len; tpm_sha1_ctx_t sha1; ptr = buf; len = sizeof(buf); tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_TRANSPORT_LOG_OUT); tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, &tpmData.stany.data.currentTicks); tpm_marshal_BLOB(&ptr, &len, params, SHA1_DIGEST_LENGTH); tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, tpmData.stany.flags.localityModifier); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, transDigest->digest, sizeof(transDigest->digest)); tpm_sha1_update(&sha1, buf, sizeof(buf)); tpm_sha1_final(&sha1, transDigest->digest); debug_buf("LogOut: transDigest: ", transDigest->digest, sizeof(transDigest->digest)); } TPM_RESULT TPM_EstablishTransport(TPM_KEY_HANDLE encHandle, TPM_TRANSPORT_PUBLIC *transPublic, UINT32 secretSize, BYTE *secret, TPM_AUTH *auth1, TPM_TRANSHANDLE *transHandle, TPM_MODIFIER_INDICATOR *locality, TPM_CURRENT_TICKS *currentTicks, TPM_NONCE *transNonceEven) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_TRANSPORT_AUTH trans_auth; TPM_SESSION_DATA *session; info("TPM_EstablishTransport()"); /* setup authorization data */ if (encHandle == TPM_KH_TRANSPORT) { if (auth1->authHandle != TPM_INVALID_HANDLE) return TPM_BADTAG; if (transPublic->transAttributes & TPM_TRANSPORT_ENCRYPT) return TPM_BAD_SCHEME; if (secretSize != 20) return TPM_BAD_PARAM_SIZE; memcpy(trans_auth.authData, secret, 20); } else { /* get key and verify its usage */ key = tpm_get_key(encHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; if (key->keyUsage != TPM_KEY_STORAGE && key->keyUsage != TPM_KEY_LEGACY) return TPM_INVALID_KEYUSAGE; /* verify authorization */ if (key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, encHandle); if (res != TPM_SUCCESS) return res; if (decrypt_transport_auth(key, secret, secretSize, &trans_auth)) return TPM_DECRYPT_ERROR; } } /* check whether the transport has to be encrypted */ if (transPublic->transAttributes & TPM_TRANSPORT_ENCRYPT) { if (tpmData.permanent.flags.FIPS && transPublic->algID == TPM_ALG_MGF1) return TPM_INAPPROPRIATE_ENC; /* until now, only MGF1 is supported */ if (transPublic->algID != TPM_ALG_MGF1) return TPM_BAD_KEY_PROPERTY; } /* initialize transport session */ tpm_get_random_bytes(transNonceEven->nonce, sizeof(transNonceEven->nonce)); *transHandle = tpm_get_free_session(TPM_ST_TRANSPORT); session = tpm_get_transport(*transHandle); if (session == NULL) return TPM_RESOURCES; session->transInternal.transHandle = *transHandle; memset(&session->transInternal.transDigest, 0, sizeof(TPM_DIGEST)); memcpy(&session->transInternal.transPublic, transPublic, sizeof_TPM_TRANSPORT_PUBLIC((*transPublic))); memcpy(&session->transInternal.transNonceEven, transNonceEven, sizeof(TPM_NONCE)); memcpy(&session->nonceEven, transNonceEven, sizeof(TPM_NONCE)); memcpy(&session->transInternal.authData, trans_auth.authData, sizeof(TPM_AUTHDATA)); *locality = tpmData.stany.flags.localityModifier; memcpy(currentTicks, &tpmData.stany.data.currentTicks, sizeof(TPM_CURRENT_TICKS)); /* perform transport logging */ if (transPublic->transAttributes & TPM_TRANSPORT_LOG) { tpm_sha1_ctx_t sha1; BYTE *ptr, buf[4 + 4 + 4 + sizeof_TPM_CURRENT_TICKS(x) + 20]; UINT32 len; /* log input */ memset(buf, 0, sizeof(buf)); transport_log_in(auth1->digest, buf, &session->transInternal.transDigest); /* compute digest of output parameters and log output */ ptr = buf; len = sizeof(buf); tpm_marshal_UINT32(&ptr, &len, TPM_SUCCESS); tpm_marshal_TPM_COMMAND_CODE(&ptr, &len, TPM_ORD_EstablishTransport); tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, *locality); tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, currentTicks); tpm_marshal_TPM_NONCE(&ptr, &len, transNonceEven); tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, buf, sizeof(buf)); tpm_sha1_final(&sha1, buf); transport_log_out(buf, &session->transInternal.transDigest); } /* check whether this is a exclusive transport session */ if (transPublic->transAttributes & TPM_TRANSPORT_EXCLUSIVE) { tpmData.stany.flags.transportExclusive = TRUE; tpmData.stany.data.transExclusive = *transHandle; } auth1->continueAuthSession = FALSE; return TPM_SUCCESS; } extern UINT32 tpm_get_in_param_offset(TPM_COMMAND_CODE ordinal); extern UINT32 tpm_get_out_param_offset(TPM_COMMAND_CODE ordinal); extern void tpm_compute_in_param_digest(TPM_REQUEST *req); extern void tpm_execute_command(TPM_REQUEST *req, TPM_RESPONSE *rsp); extern void tpm_compute_out_param_digest(TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp); static void decrypt_wrapped_command(BYTE *buf, UINT32 buf_len, TPM_AUTH *auth, TPM_SESSION_DATA *session) { UINT32 i, j; BYTE mask[SHA1_DIGEST_LENGTH]; tpm_sha1_ctx_t sha1; for (i = 0; buf_len > 0; i++) { tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, session->nonceEven.nonce, sizeof(session->nonceEven.nonce)); tpm_sha1_update(&sha1, auth->nonceOdd.nonce, sizeof(auth->nonceOdd.nonce)); tpm_sha1_update(&sha1, (uint8_t*)"in", 2); tpm_sha1_update(&sha1, session->transInternal.authData, sizeof(TPM_SECRET)); tpm_sha1_update_be32(&sha1, i); tpm_sha1_final(&sha1, mask); for (j = 0; j < sizeof(mask) && buf_len > 0; j++) { *buf++ ^= mask[j]; buf_len--; } } } static void encrypt_wrapped_command(BYTE *buf, UINT32 buf_len, TPM_AUTH *auth, TPM_SESSION_DATA *session) { UINT32 i, j; BYTE mask[SHA1_DIGEST_LENGTH]; tpm_sha1_ctx_t sha1; for (i = 0; buf_len > 0; i++) { tpm_sha1_init(&sha1); tpm_sha1_update(&sha1, session->nonceEven.nonce, sizeof(session->nonceEven.nonce)); tpm_sha1_update(&sha1, auth->nonceOdd.nonce, sizeof(auth->nonceOdd.nonce)); tpm_sha1_update(&sha1, (uint8_t*)"out", 3); tpm_sha1_update(&sha1, session->transInternal.authData, sizeof(TPM_SECRET)); tpm_sha1_update_be32(&sha1, i); tpm_sha1_final(&sha1, mask); for (j = 0; j < sizeof(mask) && buf_len > 0; j++) { *buf++ ^= mask[j]; buf_len--; } } } static void compute_key_digest(TPM_REQUEST *req, TPM_DIGEST *digest) { tpm_sha1_ctx_t ctx; TPM_HANDLE h1, h2; TPM_KEY_DATA *k1, *k2; BYTE *ptr; UINT32 len, offset = tpm_get_in_param_offset(req->ordinal); /* handle some exceptions */ if (req->ordinal == TPM_ORD_FlushSpecific) offset = 0; else if (req->ordinal == TPM_ORD_OwnerReadInternalPub) offset = 4; /* compute public key digests */ if (offset == 0) { debug("no handles"); memset(digest, 0, sizeof(TPM_DIGEST)); } else if (offset == 4) { debug("one handle"); ptr = req->param; len = 4; tpm_unmarshal_TPM_HANDLE(&ptr, &len, &h1); k1 = tpm_get_key(h1); if (k1 != NULL && tpm_compute_key_data_digest(k1, digest) == 0) { debug("key found"); /* compute outer hash */ tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, digest->digest, sizeof(digest->digest)); tpm_sha1_final(&ctx, digest->digest); } else { memset(digest, 0, sizeof(TPM_DIGEST)); } } else if (offset == 8) { TPM_DIGEST digest2; debug("two handles"); ptr = req->param; len = 8; tpm_unmarshal_TPM_HANDLE(&ptr, &len, &h1); tpm_unmarshal_TPM_HANDLE(&ptr, &len, &h2); k1 = tpm_get_key(h1); k2 = tpm_get_key(h2); if (k1 != NULL && tpm_compute_key_data_digest(k1, digest) == 0 && k2 != NULL && tpm_compute_key_data_digest(k2, &digest2) == 0) { debug("two keys found"); /* compute outer hash */ tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, digest->digest, sizeof(digest->digest)); tpm_sha1_update(&ctx, digest2.digest, sizeof(digest2.digest)); tpm_sha1_final(&ctx, digest->digest); } else { memset(digest, 0, sizeof(TPM_DIGEST)); } } else { memset(digest, 0, sizeof(TPM_DIGEST)); } } 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; } TPM_RESULT TPM_ReleaseTransportSigned(TPM_KEY_HANDLE keyHandle, TPM_NONCE *antiReplay, TPM_AUTH *auth1, TPM_AUTH *auth2, TPM_MODIFIER_INDICATOR *locality, TPM_CURRENT_TICKS *currentTicks, UINT32 *sigSize, BYTE **sig) { TPM_RESULT res; TPM_KEY_DATA *key; TPM_SESSION_DATA *session; BYTE buf[30 + 20]; info("TPM_ReleaseTransportSigned()"); /* get key */ key = tpm_get_key(keyHandle); if (key == NULL) return TPM_INVALID_KEYHANDLE; /* verify authorization */ if (auth2->authHandle != TPM_INVALID_HANDLE || key->authDataUsage != TPM_AUTH_NEVER) { res = tpm_verify_auth(auth1, key->usageAuth, keyHandle); if (res != TPM_SUCCESS) return res; session = tpm_get_transport(auth2->authHandle); if (session == NULL) return TPM_INVALID_AUTHHANDLE; res = tpm_verify_auth(auth2, session->transInternal.authData, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res; } else { session = tpm_get_transport(auth1->authHandle); if (session == NULL) return TPM_INVALID_AUTHHANDLE; res = tpm_verify_auth(auth1, session->transInternal.authData, TPM_INVALID_HANDLE); if (res != TPM_SUCCESS) return res; } /* invalidate transport session */ auth1->continueAuthSession = FALSE; /* logging must be enabled */ if (!(session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_LOG)) return TPM_BAD_MODE; *locality = tpmData.stany.flags.localityModifier; memcpy(currentTicks, &tpmData.stany.data.currentTicks, sizeof(TPM_CURRENT_TICKS)); transport_log_out(auth1->digest, &session->transInternal.transDigest); /* setup a TPM_SIGN_INFO structure */ memcpy(&buf[0], (uint8_t*)"\x00\x05TRAN", 6); memcpy(&buf[6], antiReplay->nonce, 20); memcpy(&buf[26], (uint8_t*)"\x00\x00\x00\x14", 4); memcpy(&buf[30], session->transInternal.transDigest.digest, 20); /* sign info structure */ if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { tpm_sha1_ctx_t ctx; debug("TPM_SS_RSASSAPKCS1v15_SHA1"); tpm_sha1_init(&ctx); tpm_sha1_update(&ctx, buf, sizeof(buf)); tpm_sha1_final(&ctx, buf); res = tpm_sign(key, auth1, FALSE, buf, SHA1_DIGEST_LENGTH, sig, sigSize); } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) { debug("TPM_SS_RSASSAPKCS1v15_INFO"); res = tpm_sign(key, auth1, TRUE, buf, sizeof(buf), sig, sigSize); } else { debug("unsupported signature scheme: %02x", key->sigScheme); res = TPM_INVALID_KEYUSAGE; } return res; } ================================================ FILE: tpmd/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 364 2010-02-11 10:24:45Z mast $ if(UNIX) add_subdirectory(unix) elseif(WIN32) add_subdirectory(windows) endif() ================================================ FILE: tpmd/unix/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 464 2011-07-09 14:57:41Z mast $ include_directories("${PROJECT_SOURCE_DIR}/tpm") file(GLOB tpmd_SRCS "*.[h|c]") add_executable(tpmd ${tpmd_SRCS}) if(MTM_EMULATOR) add_definitions(-DMTM_EMULATOR) target_link_libraries(tpmd mtm tpm tpm_crypto) else() target_link_libraries(tpmd tpm tpm_crypto) endif() install(TARGETS tpmd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ================================================ FILE: tpmd/unix/tpmd.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * This program 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 program 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: tpmd.c 463 2011-06-08 14:25:04Z mast $ */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "tpm/tpm_emulator.h" #define TPM_COMMAND_TIMEOUT 30 static volatile int stopflag = 0; static int is_daemon = 0; static int opt_debug = 0; static int opt_foreground = 0; static const char default_socket_name[] = TPM_SOCKET_NAME; static const char *opt_socket_name = default_socket_name; static const char default_dev_name[] = "/dev/tpm_emul"; static const char *opt_dev_name = default_dev_name; static uid_t opt_uid = 0; static gid_t opt_gid = 0; static int tpm_startup = 2; static uint32_t tpm_config = 0; extern const char *tpm_storage_file; void my_log(int priority, const char *fmt, ...) { va_list ap, bp; va_start(ap, fmt); va_copy(bp, ap); switch (priority) { case TPM_LOG_DEBUG: vsyslog(LOG_DEBUG, fmt, ap); break; case TPM_LOG_ERROR: vsyslog(LOG_ERR, fmt, ap); break; case TPM_LOG_INFO: default: vsyslog(LOG_INFO, fmt, ap); break; } va_end(ap); if (!is_daemon && (priority != TPM_LOG_DEBUG || opt_debug)) { vprintf(fmt, bp); } va_end(bp); } static void print_usage(char *name) { printf("usage: %s [-d] [-f] [-s storage file] [-u unix socket name] " "[-o user name] [-g group name] [-h] [startup mode]\n", name); printf(" d : enable debug mode\n"); printf(" f : forces the application to run in the foreground\n"); printf(" s : storage file to use (default: %s)\n", tpm_storage_file); printf(" u : unix socket name to use (default: %s)\n", default_socket_name); printf(" U : don't use unix socket\n"); printf(" e : emulation device to use (default: %s)\n", default_dev_name); printf(" E : don't use emulation device\n"); printf(" o : effective user the application should run as\n"); printf(" g : effective group the application should run as\n"); printf(" h : print this help message\n"); printf(" startup mode : must be 'clear', " "'save' (default) or 'deactivated\n"); } static void parse_options(int argc, char **argv) { int c, set_dev = 0; struct passwd *pwd; struct group *grp; opt_uid = getuid(); opt_gid = getgid(); info("parsing options"); while ((c = getopt (argc, argv, "dfs:u:Ue:Eo:g:c:h")) != -1) { debug("handling option '-%c'", c); switch (c) { case 'd': opt_debug = 1; setlogmask(setlogmask(0) | LOG_MASK(LOG_DEBUG)); debug("debug mode enabled"); break; case 'f': debug("application is forced to run in foreground"); opt_foreground = 1; break; case 's': tpm_storage_file = optarg; debug("using storage file '%s'", tpm_storage_file); break; case 'u': opt_socket_name = optarg; debug("using unix socket '%s'", opt_socket_name); break; case 'U': opt_socket_name = NULL; break; case 'e': opt_dev_name = optarg; set_dev = 1; debug("using emulation device '%s'", opt_dev_name); break; case 'E': opt_dev_name = NULL; set_dev = 0; break; case 'o': pwd = getpwnam(optarg); if (pwd == NULL) { error("invalid user name '%s'\n", optarg); exit(EXIT_FAILURE); } opt_uid = pwd->pw_uid; break; case 'g': grp = getgrnam(optarg); if (grp == NULL) { error("invalid group name '%s'\n", optarg); exit(EXIT_FAILURE); } opt_gid = grp->gr_gid; break; case 'c': tpm_config = strtol(optarg, NULL, 0); debug("tpm_config = %04x", tpm_config); break; case '?': error("unknown option '-%c'", optopt); print_usage(argv[0]); exit(EXIT_FAILURE); case 'h': default: print_usage(argv[0]); exit(EXIT_SUCCESS); } } if (set_dev == 0 && access(opt_dev_name, F_OK) < 0) opt_dev_name = NULL; if (!opt_socket_name && !opt_dev_name) { error("both socket and emulator device are unavailable\n"); print_usage(argv[0]); exit(EXIT_FAILURE); } if (optind < argc) { debug("startup mode = '%s'", argv[optind]); if (!strcmp(argv[optind], "clear")) { tpm_startup = 1; } else if (!strcmp(argv[optind], "save")) { tpm_startup = 2; } else if (!strcmp(argv[optind], "deactivated")) { tpm_startup = 3; } else { error("invalid startup mode '%s'; must be 'clear', " "'save' (default) or 'deactivated", argv[optind]); print_usage(argv[0]); exit(EXIT_SUCCESS); } } else { /* if no startup mode is given assume save if a configuration file is available, clear otherwise */ int fh = open(tpm_storage_file, O_RDONLY); if (fh < 0) { tpm_startup = 1; info("no startup mode was specified; asuming 'clear'"); } else { tpm_startup = 2; close(fh); } } } static void switch_uid_gid(void) { if (opt_gid != getgid()) { info("switching effective group ID to %d", opt_gid); if (setgid(opt_gid) == -1) { error("switching effective group ID to %d failed: %s", opt_gid, strerror(errno)); exit(EXIT_FAILURE); } } if (opt_uid != getuid()) { info("switching effective user ID to %d", opt_uid); if (setuid(opt_uid) == -1) { error("switching effective user ID to %d failed: %s", opt_uid, strerror(errno)); exit(EXIT_FAILURE); } } } static void signal_handler(int sig) { info("signal received: %d", sig); if (sig == SIGTERM || sig == SIGQUIT || sig == SIGINT) stopflag = 1; } static void init_signal_handler(void) { info("installing signal handlers"); if (signal(SIGTERM, signal_handler) == SIG_ERR) { error("signal(SIGTERM) failed: %s", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGQUIT, signal_handler) == SIG_ERR) { error("signal(SIGQUIT) failed: %s", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGINT, signal_handler) == SIG_ERR) { error("signal(SIGINT) failed: %s", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGPIPE, signal_handler) == SIG_ERR) { error("signal(SIGPIPE) failed: %s", strerror(errno)); exit(EXIT_FAILURE); } } static void daemonize(void) { pid_t sid, pid, fd; info("daemonizing process"); pid = fork(); if (pid < 0) { error("fork() failed: %s", strerror(errno)); exit(EXIT_FAILURE); } if (pid > 0) exit(EXIT_SUCCESS); pid = getpid(); sid = setsid(); if (sid < 0) { error("setsid() failed: %s", strerror(errno)); exit(EXIT_FAILURE); } if (chdir("/") < 0) { error("chdir() failed: %s", strerror(errno)); exit(EXIT_FAILURE); } fd = open("/dev/null", O_RDWR); if (fd < 0) { error("open(/dev/null) failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); is_daemon = 1; info("process was successfully daemonized: pid=%d sid=%d", pid, sid); } static int mkdirs(const char *path) { char *copy = strdup(path); char *p = strchr(copy + 1, '/'); while (p != NULL) { *p = '\0'; if ((mkdir(copy, 0755) == -1) && (errno != EEXIST)) { free(copy); return errno; } *p = '/'; p = strchr(p + 1, '/'); } free(copy); return 0; } static int init_socket(const char *name) { int sock; struct sockaddr_un addr; info("initializing socket %s", name); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { error("socket(AF_UNIX) failed: %s", strerror(errno)); return -1; } mkdirs(name); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, name, sizeof(addr.sun_path)-1); umask(0177); if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { error("bind(%s) failed: %s", addr.sun_path, strerror(errno)); close(sock); return -1; } listen(sock, 1); return sock; } static int init_device(const char *name) { int devfd, flags; info("initializing device %s", name); devfd = open(name, O_RDWR); if (devfd < 0) { error("open(%s) failed: %s", name, strerror(errno)); return -1; } flags = fcntl(devfd, F_GETFL); if (flags == -1) { error("fcntl(%s, F_GETFL) failed: %s", name, strerror(errno)); close(devfd); return -1; } if (fcntl(devfd, F_SETFL, flags | O_NONBLOCK) == -1) { error("fcntl(%s, F_SETFL) failed: %s", name, strerror(errno)); close(devfd); return -1; } return devfd; } 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 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"); if (sock >= 0) close(sock); if (opt_socket_name) 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)); break; } else if (res == 0) { #ifdef TPMD_DISCONNECT_IDLE_CLIENTS info("connection closed due to inactivity"); break; #else continue; #endif } if (devfd != -1 && 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 */ if (sock >= 0) close(sock); if (opt_socket_name) unlink(opt_socket_name); if (devfd >= 0) close(devfd); info("main loop stopped"); } int main(int argc, char **argv) { openlog(argv[0], 0, LOG_DAEMON); setlogmask(~LOG_MASK(LOG_DEBUG)); syslog(LOG_INFO, "--- separator ---\n"); tpm_log = my_log; info("starting TPM Emulator daemon (1.2.%d.%d-%d)", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); parse_options(argc, argv); /* switch uid/gid if required */ switch_uid_gid(); /* init signal handlers */ init_signal_handler(); /* unless requested otherwiese, fork and daemonize process */ if (!opt_foreground) daemonize(); /* start main processing loop */ main_loop(); info("stopping TPM Emulator daemon"); closelog(); return EXIT_SUCCESS; } ================================================ FILE: tpmd/windows/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 464 2011-07-09 14:57:41Z mast $ include_directories("${PROJECT_SOURCE_DIR}/tpm") file(GLOB tpmd_SRCS "*.[h|c]") add_executable(tpmd ${tpmd_SRCS}) if(MTM_EMULATOR) add_definitions(-DMTM_EMULATOR) target_link_libraries(tpmd mtm tpm tpm_crypto) else() target_link_libraries(tpmd tpm tpm_crypto) endif() install(TARGETS tpmd RUNTIME DESTINATION .) install(FILES control_tpmd.bat DESTINATION .) ================================================ FILE: tpmd/windows/control_tpmd.bat ================================================ :: Software-based Trusted Platform Module (TPM) Emulator :: Copyright (C) 2004-2010 Mario Strasser :: :: $Id: CMakeLists.txt 390 2010-02-18 10:04:12Z mast $ @echo off set SERVICE_ID=tpmd set SERVICE_NAME=TPM Emulator set SERVICE_DIR=%~dp0 set SERVICE_EXE=%SERVICE_DIR%\tpmd.exe if /i "%1" == "" goto usage if /i "%1" == "install" goto install if /i "%1" == "remove" goto remove if /i "%1" == "start" goto start if /i "%1" == "stop" goto stop if /i "%1" == "status" goto status goto usage :usage echo Usage: %0 (install, remove, start, stop, status) goto :eof :install if not exist "%SERVICE_EXE%" goto missing sc create %SERVICE_ID% binpath= "%SERVICE_EXE% \"%SERVICE_CONF%\"" DisplayName= "%SERVICE_NAME%" start= demand goto :eof :missing echo "Error: file '%SERVICE_EXE%' does not exists." goto :eof :remove sc delete %SERVICE_ID% goto :eof :start sc start %SERVICE_ID% goto :eof :stop sc stop %SERVICE_ID% goto :eof :status sc query %SERVICE_ID% goto :eof ================================================ FILE: tpmd/windows/tpmd.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * Copyright (C) 2009 Domenic Schroeder * * This program 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 program 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: tpmd.c 389 2010-02-18 09:52:11Z mast $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "tpm/tpm_emulator.h" #define SERVICE_NAME "tpmd" static volatile int stopflag = 0; static int is_service = 0; static int opt_debug = 0; static int opt_foreground = 0; static const char *opt_pipe_name = TPM_DEVICE_NAME; static int tpm_startup = 2; static uint32_t tpm_config = 0; extern const char *tpm_storage_file; extern const char *tpm_log_file; static SERVICE_STATUS_HANDLE status_handle; static DWORD current_status; void my_log(int priority, const char *fmt, ...) { FILE *fh; va_list ap, bp; time_t tv; struct tm t; time(&tv); memcpy(&t, localtime(&tv), sizeof(t)); va_start(ap, fmt); va_copy(bp, ap); fh = fopen(tpm_log_file, "a"); if (fh != NULL) { fprintf(fh, "%04d-%02d-%02d %02d:%02d:%02d ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); vfprintf(fh, fmt, ap); fclose(fh); } va_end(ap); if (!is_service && (priority != TPM_LOG_DEBUG || opt_debug)) { printf("%04d-%02d-%02d %02d:%02d:%02d ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); vprintf(fmt, bp); } va_end(bp); } static void print_usage(char *name) { printf("usage: %s [-d] [-f] [-s storage file] [-u windows pipe name] " "[-l log file] [-h] [startup mode]\n", name); printf(" d : enable debug mode\n"); printf(" f : forces the application to run in the foreground\n"); printf(" s : storage file to use (default: %s)\n", tpm_storage_file); printf(" u : windows named pipe name to use (default: %s)\n", opt_pipe_name); printf(" l : name of the log file (default: %s)\n", tpm_log_file); printf(" h : print this help message\n"); printf(" startup mode : must be 'clear', " "'save' (default) or 'deactivated\n"); } static int parse_options(int argc, char **argv) { char c; info("parsing options"); while ((c = getopt (argc, argv, "dfs:u:o:g:c:h")) != -1) { debug("handling option '-%c'", c); switch (c) { case 'd': opt_debug = 1; debug("debug mode enabled"); break; case 'f': debug("application is forced to run in foreground"); opt_foreground = 1; break; case 's': tpm_storage_file = optarg; debug("using storage file '%s'", tpm_storage_file); break; case 'u': opt_pipe_name = optarg; debug("using named pipe '%s'", opt_pipe_name); break; case 'l': tpm_log_file = optarg; debug("using log file '%s'", tpm_log_file); break; case 'c': tpm_config = strtol(optarg, NULL, 0); break; case '?': error("unknown option '-%c'", optopt); print_usage(argv[0]); return -1; case 'h': default: print_usage(argv[0]); return -1; } } if (optind < argc && argv[optind][0] != 0) { debug("startup mode = '%s'", argv[optind]); if (!strcmp(argv[optind], "clear")) { tpm_startup = 1; } else if (!strcmp(argv[optind], "save")) { tpm_startup = 2; } else if (!strcmp(argv[optind], "deactivated")) { tpm_startup = 3; } else { error("invalid startup mode '%s'; must be 'clear', " "'save' (default) or 'deactivated", argv[optind]); print_usage(argv[0]); return 0; } } else { /* if no startup mode is given assume save if a configuration file is available, clear otherwise */ int fh = open(tpm_storage_file, O_RDONLY); if (fh < 0) { tpm_startup = 1; info("no startup mode was specified; asuming 'clear'"); } else { tpm_startup = 2; close(fh); } } return 0; } static const char *get_error(void) { static char buf[512]; memset(buf, 0, sizeof(buf)); FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, "", GetLastError(), 0, buf, sizeof(buf), NULL); return buf; } BOOL signal_handler(DWORD event) { info("signal received: %d", event); stopflag = 1; /* unblock ConnectNamedPipe() */ HANDLE ph = CreateFile(opt_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (ph != INVALID_HANDLE_VALUE) CloseHandle(ph); return TRUE; } static int init_signal_handler(void) { info("installing signal handler"); if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)signal_handler,TRUE)) { error("SetConsoleCtrlHandler() failed: %s", get_error()); return -1; } return 0; } static void main_loop(void) { HANDLE ph; DWORD in_len; uint32_t out_len; BYTE in[TPM_CMD_BUF_SIZE]; uint8_t *out; info("staring main loop"); /* open named pipe */ ph = CreateNamedPipe(opt_pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, TPM_CMD_BUF_SIZE, TPM_CMD_BUF_SIZE, 0, NULL); if (ph == INVALID_HANDLE_VALUE) { error("CreateNamedPipe() failed: %s", get_error()); return; } /* init tpm emulator */ debug("initializing TPM emulator"); if (tpm_emulator_init(tpm_startup, tpm_config) != 0) { error("tpm_emulator_init() failed"); CloseHandle(ph); return; } /* start command processing */ while (!stopflag) { /* wait for incomming connections */ debug("waiting for connections..."); if (!ConnectNamedPipe(ph, NULL)) { error("ConnectNamedPipe() failed: %s", get_error()); break; } if (stopflag) break; /* receive and handle commands */ in_len = 0; do { if (!ReadFile(ph, in, sizeof(in), &in_len, NULL)) { error("ReadFile() failed: %s", get_error()); } if (in_len > 0) { debug("received %d bytes", in_len); out = NULL; if (tpm_handle_command(in, in_len, &out, &out_len) != 0) { error("tpm_handle_command() failed"); } else { debug("sending %d bytes", out_len); DWORD res, len = 0; while (len < out_len) { if (!WriteFile(ph, out, out_len, &res, NULL)) { error("WriteFile(%d) failed: %s", out_len - len, strerror(errno)); break; } len += res; } tpm_free(out); } } } while (in_len > 0 && !stopflag); DisconnectNamedPipe(ph); } /* shutdown tpm emulator */ tpm_emulator_shutdown(); /* close socket */ CloseHandle(ph); info("main loop stopped"); } BOOL updateServiceStatus(DWORD currentState, DWORD winExitCode, DWORD exitCode, DWORD checkPoint, DWORD waitHint) { SERVICE_STATUS status; /* if this is a service update the status, otherwise return success */ if (!is_service) return TRUE; current_status = currentState; status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; status.dwCurrentState = currentState; /* once the service is up and running, it accepts the events stop and shutdown */ if (currentState == SERVICE_START_PENDING) { status.dwControlsAccepted = 0; } else { status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; } status.dwWin32ExitCode = winExitCode; status.dwServiceSpecificExitCode = exitCode; status.dwCheckPoint = checkPoint; status.dwWaitHint = waitHint; return SetServiceStatus(status_handle, &status); } void serviceCtrlHandler(DWORD code) { switch (code) { /* stop service if told so or in the case of a system shutdown */ case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: updateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000); signal_handler(CTRL_CLOSE_EVENT); break; /* report the current status of the service to the SCM */ case SERVICE_CONTROL_INTERROGATE: updateServiceStatus(current_status, NO_ERROR, 0, 0, 0); break; } } void serviceMain(int argc, char **argv) { info("starting TPM Emulator daemon (1.2.%d.%d-%d)", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); /* first of all register the control handler function of the service */ if (is_service) { status_handle = RegisterServiceCtrlHandler( SERVICE_NAME, (LPHANDLER_FUNCTION)serviceCtrlHandler); } if (argc > 0 && parse_options(argc, argv) != 0) { updateServiceStatus(SERVICE_STOPPED, ERROR_SERVICE_SPECIFIC_ERROR, 1, 0, 0); return; } tpm_log = my_log; /* init signal handler */ if (init_signal_handler() != 0) { updateServiceStatus(SERVICE_STOPPED, ERROR_SERVICE_SPECIFIC_ERROR, 1, 0, 0); return; } /* start main processing loop */ updateServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0); main_loop(); info("stopping TPM Emulator daemon"); updateServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0); } int main(int argc, char **argv) { if (parse_options(argc, argv) != 0) return EXIT_FAILURE; if (opt_foreground) { is_service = 0; serviceMain(0, NULL); return EXIT_SUCCESS; } else { SERVICE_TABLE_ENTRY service_table[] = { { (LPTSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, { NULL, NULL } }; is_service = 1; StartServiceCtrlDispatcher(service_table); return GetLastError(); } } ================================================ FILE: tpmd_dev/CMakeLists.txt ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: CMakeLists.txt 453 2010-09-11 11:00:58Z mast $ # select matching module sources if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(tpmd_dev_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/linux") set(tpmd_dev_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/linux") set(tpmd_dev_OBJ "${tpmd_dev_BINARY_DIR}/tpmd_dev.ko") if(CMAKE_COMPILER_IS_GNUCC) set(tpmd_dev_BUILD_CMD make -C ${tpmd_dev_BINARY_DIR} CC=${CMAKE_C_COMPILER} LD=${CMAKE_LINKER}) set(tpmd_dev_INSTALL_CMD make -C ${tpmd_dev_BINARY_DIR} CC=${CMAKE_C_COMPILER} LD=${CMAKE_LINKER} install) else() set(tpmd_dev_BUILD_CMD make -C ${tpmd_dev_BINARY_DIR}) set(tpmd_dev_INSTALL_CMD make -C ${tpmd_dev_BINARY_DIR} install) endif() elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") set(tpmd_dev_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/openbsd") set(tpmd_dev_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/openbsd") set(tpmd_dev_OBJ "${tpmd_dev_BINARY_DIR}/tpmd_dev.o") set(tpmd_dev_BUILD_CMD gmake -C ${tpmd_dev_BINARY_DIR}) set(tpmd_dev_INSTALL_CMD gmake -C ${tpmd_dev_BINARY_DIR} install) elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(tpmd_dev_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/darwin") set(tpmd_dev_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/darwin") set(tpmd_dev_OBJ "${tpmd_dev_BINARY_DIR}/build/Release/tpm_bridge.kext") set(tpmd_dev_BUILD_CMD make -C ${tpmd_dev_BINARY_DIR}) set(tpmd_dev_INSTALL_CMD make -C ${tpmd_dev_BINARY_DIR} install) endif() # compile module if(tpmd_dev_OBJ) file(GLOB tpmd_dev_SRCS "${tpmd_dev_SOURCE_DIR}/*") add_custom_command(OUTPUT ${tpmd_dev_OBJ} COMMAND cp -rf ${tpmd_dev_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} COMMAND cp ${CMAKE_BINARY_DIR}/config.h ${tpmd_dev_BINARY_DIR} COMMAND ${tpmd_dev_BUILD_CMD} DEPENDS ${tpmd_dev_SRCS}) add_custom_target(tpmd_dev ALL DEPENDS ${tpmd_dev_OBJ}) install(CODE "EXECUTE_PROCESS(COMMAND ${tpmd_dev_INSTALL_CMD})") endif() ================================================ FILE: tpmd_dev/darwin/Info.plist ================================================ CFBundleDevelopmentRegion English CFBundleExecutable tpm_bridge CFBundleIdentifier com.osxbook.kext.tpmbridge CFBundleInfoDictionaryVersion 6.0 CFBundleName TPM Emulator Bridge CFBundlePackageType KEXT CFBundleVersion 1.0.0d1 NSHumanReadableCopyright © Amit Singh, 2009-2010 OSBundleLibraries com.apple.kpi.bsd 9.0.0 com.apple.kpi.libkern 9.0.0 ================================================ FILE: tpmd_dev/darwin/Makefile ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: Makefile 423 2010-02-22 16:32:22Z mast $ KEXT_NAME = tpm_bridge.kext KEXT_BIN = build/Release/$(KEXT_NAME) KEXT_DIR = $(DESTDIR)/System/Library/Extensions all: @xcodebuild > /dev/null clean: @xcodebuild clean > /dev/null TPM_OWNER ?= root TPM_GROUP ?= wheel install: $(KEXT_BIN) @mkdir -p $(KEXT_DIR) @cp -Rp $(KEXT_BIN) $(KEXT_DIR) @chown -R $(TPM_OWNER):$(TPM_GROUP) $(KEXT_DIR)/$(KEXT_NAME) .PHONY: all clean install ================================================ FILE: tpmd_dev/darwin/tpm_bridge.c ================================================ /* * Copyright (c) 2009-2010 Amit Singh. All Rights Reserved. * http://osxbook.com * * TPM Emulator Device Bridge for Mac OS X * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR “AS IS” AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" /* configurable */ #define TPM_BRIDGE_NAME "tpm" /* bridge device file name (/dev/tpm) */ #define TPM_BRIDGE_MODE 0666 /* world readable/writable by default */ #define TPM_BRIDGE_UID UID_ROOT /* bridge device file owner ID */ #define TPM_BRIDGE_GID GID_WHEEL /* bridge device file group ID */ /* buffer */ static char tpm_buffer[TPM_CMD_BUF_SIZE] = { 0 }; /* locking */ static lck_grp_attr_t* tpm_mtx_grp_attr = NULL; static lck_grp_t* tpm_mtx_grp = NULL; static lck_attr_t* tpm_mtx_attr = NULL; static lck_mtx_t* tpm_mtx = NULL; /* user socket */ errno_t sock_nointerrupt(socket_t sock, int on); static SInt32 tpm_activity = 0; static UInt32 tpm_in_io = 0; static socket_t tpmd_socket = 0; static struct sockaddr_un tpmd_socket_addr = { sizeof(struct sockaddr_un), AF_LOCAL, TPM_SOCKET_NAME, }; /* device */ static int dev_tpm_index = -1; static const int dev_tpm_minor = 0; static void* dev_tpm_node = NULL; d_open_t tpm_dev_open; d_read_t tpm_dev_read; d_write_t tpm_dev_write; extern int seltrue(dev_t, int, struct proc*); static struct cdevsw cdev_tpm = { tpm_dev_open, (d_close_t*)&nulldev, tpm_dev_read, tpm_dev_write, (d_ioctl_t*)&enodev, (d_stop_t*)&nulldev, (d_reset_t*)&nulldev, 0, (select_fcn_t*)seltrue, eno_mmap, eno_strat, eno_getc, eno_putc, D_TTY, }; static int tpmd_connect(void); static void tpmd_disconnect(void); kern_return_t tpm_bridge_start(kmod_info_t* ki, void* d); kern_return_t tpm_bridge_stop(kmod_info_t* ki, void* d); static int tpm_bridge_locking_start(void); static int tpm_bridge_locking_stop(void); static int tpm_bridge_devfs_start(void); static int tpm_bridge_devfs_stop(void); int tpm_dev_open(dev_t dev, int flags, int devtype, struct proc* p) { (void)OSIncrementAtomic(&tpm_activity); int error = 0; lck_mtx_lock(tpm_mtx); if ((tpmd_socket == NULL) || !sock_isconnected(tpmd_socket)) { if (tpmd_connect() != 0) { tpmd_socket = NULL; lck_mtx_unlock(tpm_mtx); error = ECONNREFUSED; goto out; } } lck_mtx_unlock(tpm_mtx); out: (void)OSDecrementAtomic(&tpm_activity); return error; } int tpm_dev_read(dev_t dev, struct uio* uio, int ioflag) { (void)OSIncrementAtomic(&tpm_activity); errno_t error = 0; size_t recvlen; struct msghdr msg; struct iovec aiov[1]; lck_mtx_lock(tpm_mtx); if ((tpmd_socket == NULL) || !sock_isconnected(tpmd_socket)) { lck_mtx_unlock(tpm_mtx); error = ENOTCONN; goto out; } if (tpm_in_io) { error = msleep(&tpm_in_io, tpm_mtx, PCATCH, "tpm_in_io", NULL); if (error != 0) { lck_mtx_unlock(tpm_mtx); error = EAGAIN; goto out; } } tpm_in_io = 1; lck_mtx_unlock(tpm_mtx); (void)sock_nointerrupt(tpmd_socket, 1); recvlen = (uint32_t)uio_resid(uio); memset(&msg, 0, sizeof(msg)); aiov[0].iov_base = (caddr_t)tpm_buffer; aiov[0].iov_len = TPM_CMD_BUF_SIZE; if (recvlen < TPM_CMD_BUF_SIZE) { aiov[0].iov_len = recvlen; } msg.msg_iovlen = 1; msg.msg_iov = aiov; if ((error = sock_receive(tpmd_socket, &msg, 0, (size_t*)&recvlen)) == 0) { error = uiomove64((addr64_t)(uintptr_t)tpm_buffer, (int)recvlen, uio); } lck_mtx_lock(tpm_mtx); tpm_in_io = 0; wakeup_one((caddr_t)&tpm_in_io); lck_mtx_unlock(tpm_mtx); out: (void)OSDecrementAtomic(&tpm_activity); return error; } int tpm_dev_write(dev_t dev, struct uio* uio, int ioflag) { (void)OSIncrementAtomic(&tpm_activity); errno_t error = 0; size_t sentlen; struct msghdr msg; struct iovec aiov[1]; lck_mtx_lock(tpm_mtx); if ((tpmd_socket == NULL) || !sock_isconnected(tpmd_socket)) { lck_mtx_unlock(tpm_mtx); error = ENOTCONN; goto out; } if (tpm_in_io) { error = msleep(&tpm_in_io, tpm_mtx, PCATCH, "tpm_in_io", NULL); if (error != 0) { lck_mtx_unlock(tpm_mtx); error = EAGAIN; goto out; } } tpm_in_io = 1; lck_mtx_unlock(tpm_mtx); sentlen = min((uint32_t)uio_resid(uio), TPM_CMD_BUF_SIZE); if ((error = uiomove64((addr64_t)(uintptr_t)tpm_buffer, (int)sentlen, uio)) == 0) { memset(&msg, 0, sizeof(msg)); aiov[0].iov_base = (caddr_t)tpm_buffer; aiov[0].iov_len = sentlen; msg.msg_iovlen = 1; msg.msg_iov = aiov; error = sock_send(tpmd_socket, &msg, 0, &sentlen); } lck_mtx_lock(tpm_mtx); tpm_in_io = 0; wakeup_one((caddr_t)&tpm_in_io); lck_mtx_unlock(tpm_mtx); out: (void)OSDecrementAtomic(&tpm_activity); return error; } static int tpmd_connect(void) { errno_t error; struct timeval tv; error = sock_socket(PF_LOCAL, SOCK_STREAM, 0, NULL, NULL, &tpmd_socket); if (error != 0) { tpmd_socket = NULL; return error; } tv.tv_sec = 10; tv.tv_usec = 0; error = sock_setsockopt(tpmd_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); if (error != 0) { sock_close(tpmd_socket); tpmd_socket = NULL; return error; } error = sock_connect(tpmd_socket, (const struct sockaddr*)&tpmd_socket_addr, 0); if (error != 0) { sock_close(tpmd_socket); tpmd_socket = NULL; return error; } return 0; } static void tpmd_disconnect(void) { if (tpmd_socket != NULL) { sock_shutdown(tpmd_socket, SHUT_RDWR); sock_close(tpmd_socket); tpmd_socket = NULL; } } static int tpm_bridge_locking_start(void) { tpm_mtx_grp_attr = lck_grp_attr_alloc_init(); if (tpm_mtx_grp_attr == NULL) { goto failed; } tpm_mtx_grp = lck_grp_alloc_init("tpm_mtx", tpm_mtx_grp_attr); if (tpm_mtx_grp == NULL) { goto failed; } tpm_mtx_attr = lck_attr_alloc_init(); if (tpm_mtx_attr == NULL) { goto failed; } tpm_mtx = lck_mtx_alloc_init(tpm_mtx_grp, tpm_mtx_attr); if (tpm_mtx == NULL) { goto failed; } return KERN_SUCCESS; failed: (void)tpm_bridge_locking_stop(); return KERN_FAILURE; } static int tpm_bridge_locking_stop(void) { if (tpm_mtx != NULL) { lck_mtx_free(tpm_mtx, tpm_mtx_grp); tpm_mtx = NULL; } if (tpm_mtx_attr != NULL) { lck_attr_free(tpm_mtx_attr); tpm_mtx_attr = NULL; } if (tpm_mtx_grp != NULL) { lck_grp_free(tpm_mtx_grp); tpm_mtx_grp = NULL; } if (tpm_mtx_grp_attr != NULL) { lck_grp_attr_free(tpm_mtx_grp_attr); tpm_mtx_grp_attr = NULL; } return KERN_SUCCESS; } static int tpm_bridge_devfs_start(void) { dev_tpm_index = cdevsw_add(-1, &cdev_tpm); if (dev_tpm_index == -1) { return KERN_FAILURE; } dev_tpm_node = devfs_make_node(makedev(dev_tpm_index, dev_tpm_minor), DEVFS_CHAR, TPM_BRIDGE_UID, TPM_BRIDGE_GID, TPM_BRIDGE_MODE, TPM_BRIDGE_NAME); if (dev_tpm_node == NULL) { (void)tpm_bridge_devfs_stop(); return KERN_FAILURE; } return KERN_SUCCESS; } static int tpm_bridge_devfs_stop(void) { int ret = KERN_SUCCESS; if (dev_tpm_node != NULL) { devfs_remove(dev_tpm_node); dev_tpm_node = NULL; } if (dev_tpm_index != -1) { ret = cdevsw_remove(dev_tpm_index, &cdev_tpm); if (ret != dev_tpm_index) { ret = KERN_FAILURE; } else { dev_tpm_index = -1; ret = KERN_SUCCESS; } } return ret; } kern_return_t tpm_bridge_start(kmod_info_t* ki, void* d) { if (tpm_bridge_locking_start() != KERN_SUCCESS) { return KERN_FAILURE; } if (tpm_bridge_devfs_start() != KERN_SUCCESS) { tpm_bridge_locking_stop(); return KERN_FAILURE; } #ifndef SUN_LEN #define SUN_LEN(su) \ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) #define SUN_LEN_PRIVATELY_DEFINED 1 #endif tpmd_socket_addr.sun_len = SUN_LEN(&tpmd_socket_addr); #if SUN_LEN_PRIVATELY_DEFINED #undef SUN_LEN #endif return KERN_SUCCESS; } kern_return_t tpm_bridge_stop(kmod_info_t* ki, void* d) { lck_mtx_lock(tpm_mtx); (void)tpm_bridge_devfs_stop(); if ((tpmd_socket != NULL) && sock_isconnected(tpmd_socket)) { tpmd_disconnect(); tpmd_socket = NULL; } lck_mtx_unlock(tpm_mtx); do { struct timespec ts = { 1, 0 }; (void)msleep(&tpm_activity, NULL, PUSER, "tpm_activity", &ts); } while (tpm_activity > 0); (void)tpm_bridge_locking_stop(); return KERN_SUCCESS; } ================================================ FILE: tpmd_dev/darwin/tpm_bridge.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 32A4FEBC0562C75700D090E7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; }; 32A4FEBE0562C75700D090E7 /* tpm_bridge.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A224C3CFF42312311CA2CB7 /* tpm_bridge.c */; settings = {ATTRIBUTES = (); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1A224C3CFF42312311CA2CB7 /* tpm_bridge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tpm_bridge.c; sourceTree = ""; }; 32A4FEC30562C75700D090E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32A4FEC40562C75800D090E7 /* tpm_bridge.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = tpm_bridge.kext; sourceTree = BUILT_PRODUCTS_DIR; }; D27513B306A6225300ADB3A4 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = /System/Library/Frameworks/Kernel.framework; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 32A4FEBF0562C75700D090E7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 089C166AFE841209C02AAC07 /* tpm_bridge */ = { isa = PBXGroup; children = ( 247142CAFF3F8F9811CA285C /* Source */, 089C167CFE841241C02AAC07 /* Resources */, D27513B306A6225300ADB3A4 /* Kernel.framework */, 19C28FB6FE9D52B211CA2CBB /* Products */, ); name = tpm_bridge; sourceTree = ""; }; 089C167CFE841241C02AAC07 /* Resources */ = { isa = PBXGroup; children = ( 32A4FEC30562C75700D090E7 /* Info.plist */, 089C167DFE841241C02AAC07 /* InfoPlist.strings */, ); name = Resources; sourceTree = ""; }; 19C28FB6FE9D52B211CA2CBB /* Products */ = { isa = PBXGroup; children = ( 32A4FEC40562C75800D090E7 /* tpm_bridge.kext */, ); name = Products; sourceTree = ""; }; 247142CAFF3F8F9811CA285C /* Source */ = { isa = PBXGroup; children = ( 1A224C3CFF42312311CA2CB7 /* tpm_bridge.c */, ); name = Source; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 32A4FEBA0562C75700D090E7 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 32A4FEB80562C75700D090E7 /* tpm_bridge */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91C308733DAC0010E9CD /* Build configuration list for PBXNativeTarget "tpm_bridge" */; buildPhases = ( 32A4FEBA0562C75700D090E7 /* Headers */, 32A4FEBB0562C75700D090E7 /* Resources */, 32A4FEBD0562C75700D090E7 /* Sources */, 32A4FEBF0562C75700D090E7 /* Frameworks */, 32A4FEC00562C75700D090E7 /* Rez */, ); buildRules = ( ); dependencies = ( ); name = tpm_bridge; productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; productName = tpm_bridge; productReference = 32A4FEC40562C75800D090E7 /* tpm_bridge.kext */; productType = "com.apple.product-type.kernel-extension"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 089C1669FE841209C02AAC07 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0420; }; buildConfigurationList = 1DEB91C708733DAC0010E9CD /* Build configuration list for PBXProject "tpm_bridge" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( en, ); mainGroup = 089C166AFE841209C02AAC07 /* tpm_bridge */; projectDirPath = ""; projectRoot = ""; targets = ( 32A4FEB80562C75700D090E7 /* tpm_bridge */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 32A4FEBB0562C75700D090E7 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 32A4FEBC0562C75700D090E7 /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXRezBuildPhase section */ 32A4FEC00562C75700D090E7 /* Rez */ = { isa = PBXRezBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXRezBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 32A4FEBD0562C75700D090E7 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 32A4FEBE0562C75700D090E7 /* tpm_bridge.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 089C167DFE841241C02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 089C167EFE841241C02AAC07 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 1DEB91C408733DAC0010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; "HEADER_SEARCH_PATHS[arch=*]" = ( "./**", "/usr/local/include/**", "/opt/local/include/**", "../**", ); INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; "LIBRARY_SEARCH_PATHS[arch=*]" = ( "/opt/local/lib/**", "/usr/local/lib/**", ); MODULE_NAME = com.yourcompany.kext.tpm_bridge; MODULE_START = tpm_bridge_start; MODULE_STOP = tpm_bridge_stop; MODULE_VERSION = 1.0.0d1; PRODUCT_NAME = tpm_bridge; WRAPPER_EXTENSION = kext; }; name = Debug; }; 1DEB91C508733DAC0010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_MODEL_TUNING = G5; "HEADER_SEARCH_PATHS[arch=*]" = ( "/opt/local/include/**", "/usr/local/include/**", ); INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; "LIBRARY_SEARCH_PATHS[arch=*]" = ( "/opt/local/lib/**", "/usr/local/lib/**", ); MODULE_NAME = com.yourcompany.kext.tpm_bridge; MODULE_START = tpm_bridge_start; MODULE_STOP = tpm_bridge_stop; MODULE_VERSION = 1.0.0d1; PRODUCT_NAME = tpm_bridge; WRAPPER_EXTENSION = kext; }; name = Release; }; 1DEB91C808733DAC0010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_NONCONFORMANT_CODE_ERRORS_AS_WARNINGS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_PROTOTYPE_CONVERSION = NO; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; "SDKROOT[arch=x86_64]" = macosx10.6; STRINGS_FILE_OUTPUT_ENCODING = "UTF-8"; }; name = Debug; }; 1DEB91C908733DAC0010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_NONCONFORMANT_CODE_ERRORS_AS_WARNINGS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_PROTOTYPE_CONVERSION = NO; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VARIABLE = YES; SDKROOT = macosx; "SDKROOT[arch=x86_64]" = macosx10.6; STRINGS_FILE_OUTPUT_ENCODING = "UTF-8"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1DEB91C308733DAC0010E9CD /* Build configuration list for PBXNativeTarget "tpm_bridge" */ = { isa = XCConfigurationList; buildConfigurations = ( 1DEB91C408733DAC0010E9CD /* Debug */, 1DEB91C508733DAC0010E9CD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1DEB91C708733DAC0010E9CD /* Build configuration list for PBXProject "tpm_bridge" */ = { isa = XCConfigurationList; buildConfigurations = ( 1DEB91C808733DAC0010E9CD /* Debug */, 1DEB91C908733DAC0010E9CD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 089C1669FE841209C02AAC07 /* Project object */; } ================================================ FILE: tpmd_dev/darwin/tpm_bridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: tpmd_dev/darwin/tpm_bridge.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/WorkspaceSettings.xcsettings ================================================ IDEWorkspaceUserSettings_HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges IDEWorkspaceUserSettings_SnapshotAutomaticallyBeforeSignificantChanges ================================================ FILE: tpmd_dev/darwin/tpm_bridge.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/tpm_bridge.xcscheme ================================================ ================================================ FILE: tpmd_dev/darwin/tpm_bridge.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState tpm_bridge.xcscheme orderHint 0 SuppressBuildableAutocreation 32A4FEB80562C75700D090E7 primary ================================================ FILE: tpmd_dev/linux/Makefile ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # # $Id: Makefile 364 2010-02-11 10:24:45Z mast $ # kernel settingsRCH settings ARCH ?= $(shell uname -m) KERNEL_RELEASE := $(shell uname -r) KERNEL_BUILD ?= /lib/modules/$(KERNEL_RELEASE)/build MOD_SUBDIR := misc # module settings MODULE_NAME := tpmd_dev obj-m := $(MODULE_NAME).o # do not print "Entering directory ..." MAKEFLAGS += --no-print-directory EXTRA_CFLAGS += -Wall -Werror all: @$(MAKE) LD=$(LD) CC=$(CC) ARCH=$(ARCH) -C $(KERNEL_BUILD) M=$(CURDIR) modules clean: @$(MAKE) LD=$(LD) CC=$(CC) ARCH=$(ARCH) -C $(KERNEL_BUILD) M=$(CURDIR) clean @rm -f Modules.symvers tpmd_dev.rules TPM_GROUP ?= tss INSTALL ?= install tpmd_dev.rules: tpmd_dev.rules.in @sed -e "s/\$$TPM_GROUP/$(TPM_GROUP)/g" tpmd_dev.rules.in > tpmd_dev.rules install: tpmd_dev.rules @$(MAKE) LD=$(LD) CC=$(CC) ARCH=$(ARCH) -C $(KERNEL_BUILD) M=$(CURDIR) INSTALL_MOD_PATH=$(DESTDIR) modules_install @$(INSTALL) -m 644 -D tpmd_dev.rules $(DESTDIR)/etc/udev/rules.d/80-tpmd_dev.rules .PHONY: all clean install ================================================ FILE: tpmd_dev/linux/tpmd_dev.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * * 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: tpmd_dev.c 469 2011-09-15 15:14:13Z mast $ */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #define TPM_DEVICE_MINOR 224 #define TPM_DEVICE_ID "tpm" #define TPM_MODULE_NAME "tpmd_dev" #define TPM_STATE_IS_OPEN 0 #ifdef DEBUG #define debug(fmt, ...) printk(KERN_DEBUG "%s %s:%d: Debug: " fmt "\n", \ TPM_MODULE_NAME, __FILE__, __LINE__, ## __VA_ARGS__) #else #define debug(fmt, ...) #endif #define info(fmt, ...) printk(KERN_INFO "%s %s:%d: Info: " fmt "\n", \ TPM_MODULE_NAME, __FILE__, __LINE__, ## __VA_ARGS__) #define error(fmt, ...) printk(KERN_ERR "%s %s:%d: Error: " fmt "\n", \ TPM_MODULE_NAME, __FILE__, __LINE__, ## __VA_ARGS__) #define alert(fmt, ...) printk(KERN_ALERT "%s %s:%d: Alert: " fmt "\n", \ TPM_MODULE_NAME, __FILE__, __LINE__, ## __VA_ARGS__) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mario Strasser "); MODULE_DESCRIPTION("Trusted Platform Module (TPM) Emulator"); MODULE_SUPPORTED_DEVICE(TPM_DEVICE_ID); /* module parameters */ char *tpmd_socket_name = TPM_SOCKET_NAME; module_param(tpmd_socket_name, charp, 0444); MODULE_PARM_DESC(tpmd_socket_name, " Sets the name of the TPM daemon socket."); /* TPM lock */ static struct semaphore tpm_mutex; /* TPM request buffer */ static char req_buf[TPM_CMD_BUF_SIZE]; /* TPM command response */ static struct { uint8_t *data; uint32_t size; } tpm_response; /* module state */ static uint32_t module_state; static struct socket *tpmd_sock; static struct sockaddr_un addr; static int tpmd_connect(char *socket_name) { int res; res = sock_create(PF_UNIX, SOCK_STREAM, 0, &tpmd_sock); if (res != 0) { error("sock_create() failed: %d\n", res); tpmd_sock = NULL; return res; } addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path)-1); res = tpmd_sock->ops->connect(tpmd_sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_un), 0); if (res != 0) { error("sock_connect() failed: %d\n", res); sock_release(tpmd_sock); tpmd_sock = NULL; return res; } return 0; } static void tpmd_disconnect(void) { if (tpmd_sock != NULL) sock_release(tpmd_sock); tpmd_sock = NULL; } static int tpmd_handle_command(const uint8_t *in, uint32_t in_size) { int res; struct msghdr msg; struct kvec vec; /* send command to tpmd */ memset(&msg, 0, sizeof(msg)); vec.iov_base = (void*)in; vec.iov_len = in_size; res = kernel_sendmsg(tpmd_sock, &msg, &vec, 1, in_size); if (res < 0) { error("sock_sendmsg() failed: %d\n", res); return res; } /* receive response from tpmd */ tpm_response.size = TPM_CMD_BUF_SIZE; tpm_response.data = kmalloc(tpm_response.size, GFP_KERNEL); if (tpm_response.data == NULL) return -1; memset(&msg, 0, sizeof(msg)); vec.iov_base = (void*)tpm_response.data; vec.iov_len = tpm_response.size; res = kernel_recvmsg(tpmd_sock, &msg, &vec, 1, tpm_response.size, 0); if (res < 0) { error("sock_recvmsg() failed: %d\n", res); tpm_response.data = NULL; return res; } tpm_response.size = res; return 0; } static int tpm_open(struct inode *inode, struct file *file) { int res; debug("%s()", __FUNCTION__); if (test_and_set_bit(TPM_STATE_IS_OPEN, (void*)&module_state)) return -EBUSY; down(&tpm_mutex); res = tpmd_connect(tpmd_socket_name); up(&tpm_mutex); if (res != 0) { clear_bit(TPM_STATE_IS_OPEN, (void*)&module_state); return -EIO; } return 0; } static int tpm_release(struct inode *inode, struct file *file) { debug("%s()", __FUNCTION__); down(&tpm_mutex); if (tpm_response.data != NULL) { kfree(tpm_response.data); tpm_response.data = NULL; } tpmd_disconnect(); up(&tpm_mutex); clear_bit(TPM_STATE_IS_OPEN, (void*)&module_state); return 0; } static ssize_t tpm_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { debug("%s(%zd)", __FUNCTION__, count); down(&tpm_mutex); if (tpm_response.data != NULL) { count = min(count, (size_t)tpm_response.size - (size_t)*ppos); count -= copy_to_user(buf, &tpm_response.data[*ppos], count); *ppos += count; if ((size_t)tpm_response.size == (size_t)*ppos) { kfree(tpm_response.data); tpm_response.data = NULL; } } else { count = 0; } up(&tpm_mutex); return count; } static ssize_t tpm_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { debug("%s(%zd)", __FUNCTION__, count); if (count > sizeof(req_buf)) return -EFAULT; down(&tpm_mutex); *ppos = 0; if (tpm_response.data != NULL) { kfree(tpm_response.data); tpm_response.data = NULL; } if (copy_from_user(req_buf, buf, count)) { up(&tpm_mutex); return -EFAULT; } if (tpmd_handle_command(req_buf, count) != 0) { count = -EILSEQ; tpm_response.data = NULL; } up(&tpm_mutex); return count; } #define TPMIOC_CANCEL _IO('T', 0x00) #define TPMIOC_TRANSMIT _IO('T', 0x01) static long tpm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { debug("%s(%d, %p)", __FUNCTION__, cmd, (char*)arg); if (cmd == TPMIOC_TRANSMIT) { uint32_t count; if (get_user(count, (uint32_t __user *)(arg+2))) return -EFAULT; count = be32_to_cpu(count); if (count > sizeof(req_buf)) return -EFAULT; down(&tpm_mutex); if (copy_from_user(req_buf, (void __user *)arg, count)) { up(&tpm_mutex); return -EFAULT; } if (tpm_response.data != NULL) { kfree(tpm_response.data); tpm_response.data = NULL; } if (tpmd_handle_command(req_buf, count) == 0) { tpm_response.size -= copy_to_user((char*)arg, tpm_response.data, tpm_response.size); kfree(tpm_response.data); tpm_response.data = NULL; } else { tpm_response.size = 0; tpm_response.data = NULL; } up(&tpm_mutex); return tpm_response.size; } return -1; } struct file_operations fops = { .owner = THIS_MODULE, .open = tpm_open, .release = tpm_release, .read = tpm_read, .write = tpm_write, .unlocked_ioctl = tpm_ioctl, }; static struct miscdevice tpm_dev = { .minor = TPM_DEVICE_MINOR, .name = TPM_DEVICE_ID, .fops = &fops, }; int __init init_tpm_module(void) { int res = misc_register(&tpm_dev); if (res != 0) { error("misc_register() failed for minor %d\n", TPM_DEVICE_MINOR); return res; } /* initialize variables */ sema_init(&tpm_mutex, 1); module_state = 0; tpm_response.data = NULL; tpm_response.size = 0; tpmd_sock = NULL; return 0; } void __exit cleanup_tpm_module(void) { misc_deregister(&tpm_dev); tpmd_disconnect(); if (tpm_response.data != NULL) kfree(tpm_response.data); } module_init(init_tpm_module); module_exit(cleanup_tpm_module); ================================================ FILE: tpmd_dev/linux/tpmd_dev.rules.in ================================================ KERNEL=="tpm", NAME="%k", SYMLINK+="tpm0", GROUP="$TPM_GROUP", MODE="0660" ================================================ FILE: tpmd_dev/openbsd/Makefile ================================================ # Software-based Trusted Platform Module (TPM) Emulator # Copyright (C) 2004-2010 Mario Strasser # Copyright (C) 2007 Sebastian Schuetz # # $Id$ CFLAGS= -D_KERNEL -I/usr/src/sys SRC= tpmd_dev.c OBJ= tpmd_dev.obj MODULE= tpmd_dev.o all: cc -o $(OBJ) -c $(SRC) $(CFLAGS) ld -r -o $(MODULE) $(OBJ) clean: rm -rf $(OBJ) rm -f $(MODULE) load: all mknod modload -o tpm.o -etpm $(MODULE) unload: rknod modunload -n tpm mknod: mknod -m 644 /dev/tpm c 29 0 rmnod: rm /dev/tpm install: ================================================ FILE: tpmd_dev/openbsd/tpmd_dev.c ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * Copyright (C) 2007 Sebastian Schuetz * * 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$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tpmd_dev.h" int tpmopen __P((dev_t dev, int oflags, int devtype, struct proc *p)); int tpmclose __P((dev_t dev, int fflag, int devtype, struct proc *p)); int tpmread __P((dev_t dev, struct uio *uio, int ioflag)); int tpmioctl __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)); int tpmwrite __P((dev_t dev,struct uio *uio, int ioflag)); int tpm_handler __P((struct lkm_table *lkmtp, int cmd)); /* * Provides a lkm which forwards all requests to /dev/tpm to * a local unix domain socket, reads the reply from the tpmd * and writes back to the user (tcsd) */ /* declare our character device */ cdev_decl(tpm); /* define our cdev struct containing the functions */ static struct cdevsw cdev_tpm = cdev_tpmd_init(1,tpm); /* fill in the lkm_dev structure */ MOD_DEV("tpm",LM_DT_CHAR,-1,&cdev_tpm); /* code starts */ /* test and set the bit bit on addy * there is no guarantee that this function * works on other purposes as the tpm_emulator */ int test_and_set_bit(uint32_t bit, uint32_t *addy) { int rbit = 0; uint32_t tmp, mask; tmp = *addy; tmp >>=bit; if (tmp & 0x1) { rbit = 1; } mask = 1 << bit; *addy |= mask; return rbit; } int clear_bit(uint32_t bit, uint32_t *addy) { uint32_t mask = 0x1; mask = ~(mask << bit); *addy &= mask; return 0; } /* * create a connection to our local socket file * named by socket_name */ static int tpmd_connect(char *socket_name) { int res; struct sockaddr_un *saddr; debug("%s()", __FUNCTION__); res = socreate(AF_UNIX, &tpmd_sock, SOCK_STREAM, 0); if (res != 0) { error("sock_create() failed: %d", res); tpmd_sock = NULL; return res; } nm = m_get(M_WAITOK,M_MBUF); if (nm == NULL) { error("malloc() failed"); return -1; } nm->m_len = sizeof(struct sockaddr_un); saddr = mtod(nm, struct sockaddr_un *); saddr->sun_family = AF_UNIX; saddr->sun_len = sizeof(*saddr); strlcpy(saddr->sun_path,socket_name,sizeof(saddr->sun_path)); res = soconnect(tpmd_sock,nm); if (res != 0) { error("sock_connect() failed: %d", res); m_free(nm); nm = NULL; soclose(tpmd_sock); tpmd_sock = NULL; } return res; } /* * shut down the socket and free the * mbuf struct */ static void tpmd_disconnect(void) { debug("%s()",__FUNCTION__); if (tpmd_sock != NULL) { soshutdown(tpmd_sock,SHUT_RDWR); soclose(tpmd_sock); tpmd_sock = NULL; } if (nm != NULL) { m_free(nm); nm = NULL; } } int outputData(const char *str, uint8_t *d, int len) { int i = 0; printf("%s",str); for (i = 0; i < len; i++) { printf("%.2x ",d[i]); } printf("\n"); } int tpmopen(dev_t dev, int oflags, int devtype, struct proc *p) { debug("%s()", __FUNCTION__); simple_lock(&slock); if (test_and_set_bit(TPM_STATE_IS_OPEN, (void*)&module_state)) return -EBUSY; if (tpmd_connect(tpmd_socket_name)) { tpmclose(dev,oflags,devtype,p); simple_unlock(&slock); return -1; } simple_unlock(&slock); debug("connected"); return 0; } int tpmclose(dev_t dev, int oflags, int devtype, struct proc *p) { simple_lock(&slock); debug("%s()", __FUNCTION__); tpmd_disconnect(); clear_bit(TPM_STATE_IS_OPEN, (void*)&module_state); simple_unlock(&slock); return 0; } /* * read the data and write it back */ int tpmread(dev_t dev, struct uio *uio, int ioflag) { int error; debug("%s(%u)",__FUNCTION__,uio->uio_resid); simple_lock(&slock); /* this flag is neccessary, otherwise soreceive * sometime returns EINTR */ tpmd_sock->so_rcv.sb_flags |= SB_NOINTR; error = soreceive(tpmd_sock,NULL,uio,NULL,NULL,NULL,0); if (error) { debug("soreceive() failed %i",error); } simple_unlock(&slock); return error; } /* * write the data through the socket */ int tpmwrite(dev_t dev, struct uio *uio, int ioflag) { int error; debug("%s(%d)", __FUNCTION__, uio->uio_resid); simple_lock(&slock); /* ok send the command to our socket */ if (tpmd_sock == NULL || !(tpmd_sock->so_state & SS_ISCONNECTED)) { return ENOTCONN; } error = sosend(tpmd_sock, nm ,uio ,NULL,NULL,0); if (error) { error("sosend() failed %i",error); return error; } simple_unlock(&slock); return error; } /* * The goal was not to do any "tddl" related modifications in trousers. * However I don`t know how to get the correct len of our data without * modifying the trousers ioctl call. Well trousers provides some fallback to * read/write methods, so it is not that much important to provide some * ioctl infrastructure */ int tpmioctl(dev_t dev, u_long cmd, caddr_t data, int fflag,struct proc *p) { /* tell trousers that this is not supported */ return ENODEV; } /* tpm_handler for loading/unloading */ int tpm_handler(struct lkm_table *lkmtp, int cmd) { switch (cmd) { case LKM_E_LOAD: simple_lock_init(&slock); break; case LKM_E_UNLOAD: simple_unlock(&slock); tpmclose(0,0,0,NULL); break; } return 0; } /* our main entry point */ int tpm(struct lkm_table *lkmtp, int cmd, int ver) { DISPATCH(lkmtp,cmd,ver,tpm_handler,tpm_handler,lkm_nofunc); } ================================================ FILE: tpmd_dev/openbsd/tpmd_dev.h ================================================ /* Software-based Trusted Platform Module (TPM) Emulator * Copyright (C) 2004-2010 Mario Strasser * Copyright (C) 2007 Sebastian Schuetz * * 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$ */ #ifndef _TPM_DEV_HEADER_ #define _TPM_DEV_HEADER_ #include "config.h" #define cdev_tpmd_init(c,n) { \ dev_init(c,n,open),dev_init(c,n,close),dev_init(c,n,read), \ dev_init(c,n,write), dev_init(c,n,ioctl),(dev_type_stop((*))) lkmenodev, \ 0,(dev_type_poll((*))) lkmenodev,(dev_type_mmap((*))) lkmenodev } /* This code is from linux_module.c */ /* module state */ static uint32_t module_state; static struct socket *tpmd_sock = NULL; static struct mbuf *nm = NULL; static struct simplelock slock; char tpmd_socket_name[] = TPM_SOCKET_NAME; #define TPM_MODULE_NAME "tpm_dev" #define TPM_STATE_IS_OPEN 0 #ifdef DEBUG #define debug(fmt, ...) printf("%s %s:%d: Debug: " fmt "\n", \ TPM_MODULE_NAME, __FILE__, __LINE__, ## __VA_ARGS__) #else #define debug(fmt, ...) #endif #define error(fmt, ...) printf("%s %s:%d: Error: " fmt "\n", \ TPM_MODULE_NAME, __FILE__, __LINE__, ## __VA_ARGS__) #endif /* _TPM_DEV_HEADER_ */